/*-------------------------------------------------------------------------
 *
 * nodeFuncs.c
 *		对节点树的各种通用操作
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/nodes/nodeFuncs.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/pathnodes.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"

static bool fc_expression_returns_set_walker(Node *fc_node, void *fc_context);
static int	fc_leftmostLoc(int fc_loc1, int fc_loc2);
static bool fc_fix_opfuncids_walker(Node *fc_node, void *fc_context);
static bool fc_planstate_walk_subplans(List *fc_plans, bool (*fc_walker) (),
									void *fc_context);
static bool fc_planstate_walk_members(PlanState **fc_planstates, int fc_nplans,
								   bool (*fc_walker) (), void *fc_context);


/*
 *	exprType -
 *	  返回表达式结果类型的 Oid。
 */
Oid exprType(const Node *fc_expr)
{
	Oid			fc_type;

	if (!fc_expr)
		return InvalidOid;

	switch (nodeTag(fc_expr))
	{
		case T_Var:
			fc_type = ((const Var *) fc_expr)->vartype;
			break;
		case T_Const:
			fc_type = ((const Const *) fc_expr)->consttype;
			break;
		case T_Param:
			fc_type = ((const Param *) fc_expr)->paramtype;
			break;
		case T_Aggref:
			fc_type = ((const Aggref *) fc_expr)->aggtype;
			break;
		case T_GroupingFunc:
			fc_type = INT4OID;
			break;
		case T_WindowFunc:
			fc_type = ((const WindowFunc *) fc_expr)->wintype;
			break;
		case T_SubscriptingRef:
			fc_type = ((const SubscriptingRef *) fc_expr)->refrestype;
			break;
		case T_FuncExpr:
			fc_type = ((const FuncExpr *) fc_expr)->funcresulttype;
			break;
		case T_NamedArgExpr:
			fc_type = exprType((Node *) ((const NamedArgExpr *) fc_expr)->arg);
			break;
		case T_OpExpr:
			fc_type = ((const OpExpr *) fc_expr)->opresulttype;
			break;
		case T_DistinctExpr:
			fc_type = ((const DistinctExpr *) fc_expr)->opresulttype;
			break;
		case T_NullIfExpr:
			fc_type = ((const NullIfExpr *) fc_expr)->opresulttype;
			break;
		case T_ScalarArrayOpExpr:
			fc_type = BOOLOID;
			break;
		case T_BoolExpr:
			fc_type = BOOLOID;
			break;
		case T_SubLink:
			{
				const SubLink *fc_sublink = (const SubLink *) fc_expr;

				if (fc_sublink->subLinkType == EXPR_SUBLINK ||
					fc_sublink->subLinkType == ARRAY_SUBLINK)
				{
					/* 获取子查询的第一个目标列的类型 */
					Query	   *fc_qtree = (Query *) fc_sublink->subselect;
					TargetEntry *fc_tent;

					if (!fc_qtree || !IsA(fc_qtree, Query))
						elog(ERROR, "cannot get type for untransformed sublink");
					fc_tent = linitial_node(TargetEntry, fc_qtree->targetList);
					Assert(!fc_tent->resjunk);
					fc_type = exprType((Node *) fc_tent->expr);
					if (fc_sublink->subLinkType == ARRAY_SUBLINK)
					{
						fc_type = get_promoted_array_type(fc_type);
						if (!OidIsValid(fc_type))
							ereport(ERROR,
									(errcode(ERRCODE_UNDEFINED_OBJECT),
									 errmsg("could not find array type for data type %s",
											format_type_be(exprType((Node *) fc_tent->expr)))));
					}
				}
				else if (fc_sublink->subLinkType == MULTIEXPR_SUBLINK)
				{
					/* MULTIEXPR 始终被视为返回 RECORD */
					fc_type = RECORDOID;
				}
				else
				{
					/* 对于所有其他子链接类型，结果为布尔值 */
					fc_type = BOOLOID;
				}
			}
			break;
		case T_SubPlan:
			{
				const SubPlan *fc_subplan = (const SubPlan *) fc_expr;

				if (fc_subplan->subLinkType == EXPR_SUBLINK ||
					fc_subplan->subLinkType == ARRAY_SUBLINK)
				{
					/* 获取子查询的第一个目标列的类型 */
					fc_type = fc_subplan->firstColType;
					if (fc_subplan->subLinkType == ARRAY_SUBLINK)
					{
						fc_type = get_promoted_array_type(fc_type);
						if (!OidIsValid(fc_type))
							ereport(ERROR,
									(errcode(ERRCODE_UNDEFINED_OBJECT),
									 errmsg("could not find array type for data type %s",
											format_type_be(fc_subplan->firstColType))));
					}
				}
				else if (fc_subplan->subLinkType == MULTIEXPR_SUBLINK)
				{
					/* MULTIEXPR 始终被视为返回 RECORD */
					fc_type = RECORDOID;
				}
				else
				{
					/* 对于所有其他子计划类型，结果为布尔值 */
					fc_type = BOOLOID;
				}
			}
			break;
		case T_AlternativeSubPlan:
			{
				const AlternativeSubPlan *fc_asplan = (const AlternativeSubPlan *) fc_expr;

				/* 所有子计划应返回相同的结果 */
				fc_type = exprType((Node *) linitial(fc_asplan->subplans));
			}
			break;
		case T_FieldSelect:
			fc_type = ((const FieldSelect *) fc_expr)->resulttype;
			break;
		case T_FieldStore:
			fc_type = ((const FieldStore *) fc_expr)->resulttype;
			break;
		case T_RelabelType:
			fc_type = ((const RelabelType *) fc_expr)->resulttype;
			break;
		case T_CoerceViaIO:
			fc_type = ((const CoerceViaIO *) fc_expr)->resulttype;
			break;
		case T_ArrayCoerceExpr:
			fc_type = ((const ArrayCoerceExpr *) fc_expr)->resulttype;
			break;
		case T_ConvertRowtypeExpr:
			fc_type = ((const ConvertRowtypeExpr *) fc_expr)->resulttype;
			break;
		case T_CollateExpr:
			fc_type = exprType((Node *) ((const CollateExpr *) fc_expr)->arg);
			break;
		case T_CaseExpr:
			fc_type = ((const CaseExpr *) fc_expr)->casetype;
			break;
		case T_CaseTestExpr:
			fc_type = ((const CaseTestExpr *) fc_expr)->typeId;
			break;
		case T_ArrayExpr:
			fc_type = ((const ArrayExpr *) fc_expr)->array_typeid;
			break;
		case T_RowExpr:
			fc_type = ((const RowExpr *) fc_expr)->row_typeid;
			break;
		case T_RowCompareExpr:
			fc_type = BOOLOID;
			break;
		case T_CoalesceExpr:
			fc_type = ((const CoalesceExpr *) fc_expr)->coalescetype;
			break;
		case T_MinMaxExpr:
			fc_type = ((const MinMaxExpr *) fc_expr)->minmaxtype;
			break;
		case T_SQLValueFunction:
			fc_type = ((const SQLValueFunction *) fc_expr)->type;
			break;
		case T_XmlExpr:
			if (((const XmlExpr *) fc_expr)->op == IS_DOCUMENT)
				fc_type = BOOLOID;
			else if (((const XmlExpr *) fc_expr)->op == IS_XMLSERIALIZE)
				fc_type = TEXTOID;
			else
				fc_type = XMLOID;
			break;
		case T_NullTest:
			fc_type = BOOLOID;
			break;
		case T_BooleanTest:
			fc_type = BOOLOID;
			break;
		case T_CoerceToDomain:
			fc_type = ((const CoerceToDomain *) fc_expr)->resulttype;
			break;
		case T_CoerceToDomainValue:
			fc_type = ((const CoerceToDomainValue *) fc_expr)->typeId;
			break;
		case T_SetToDefault:
			fc_type = ((const SetToDefault *) fc_expr)->typeId;
			break;
		case T_CurrentOfExpr:
			fc_type = BOOLOID;
			break;
		case T_NextValueExpr:
			fc_type = ((const NextValueExpr *) fc_expr)->typeId;
			break;
		case T_InferenceElem:
			{
				const InferenceElem *fc_n = (const InferenceElem *) fc_expr;

				fc_type = exprType((Node *) fc_n->expr);
			}
			break;
		case T_PlaceHolderVar:
			fc_type = exprType((Node *) ((const PlaceHolderVar *) fc_expr)->phexpr);
			break;
		default:
			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(fc_expr));
			fc_type = InvalidOid;	/* 保持编译器安静 */
			break;
	}
	return fc_type;
}

/*
 *	exprTypmod -
 *	  返回表达式结果类型的特定于类型的修饰符，
 *	  如果可以确定的话。在很多情况下，我们无法确定，返回 -1。
 */
int32 exprTypmod(const Node *fc_expr)
{
	if (!fc_expr)
		return -1;

	switch (nodeTag(fc_expr))
	{
		case T_Var:
			return ((const Var *) fc_expr)->vartypmod;
		case T_Const:
			return ((const Const *) fc_expr)->consttypmod;
		case T_Param:
			return ((const Param *) fc_expr)->paramtypmod;
		case T_SubscriptingRef:
			return ((const SubscriptingRef *) fc_expr)->reftypmod;
		case T_FuncExpr:
			{
				int32		fc_coercedTypmod;

				/* 智能处理长度强制函数... */
				if (exprIsLengthCoercion(fc_expr, &fc_coercedTypmod))
					return fc_coercedTypmod;
			}
			break;
		case T_NamedArgExpr:
			return exprTypmod((Node *) ((const NamedArgExpr *) fc_expr)->arg);
		case T_NullIfExpr:
			{
				/*
				 * 结果要么是第一个参数，要么是 NULL，因此如果已知，
				 * 我们可以报告第一个参数的 typmod。
				 */
				const NullIfExpr *fc_nexpr = (const NullIfExpr *) fc_expr;

				return exprTypmod((Node *) linitial(fc_nexpr->args));
			}
			break;
		case T_SubLink:
			{
				const SubLink *fc_sublink = (const SubLink *) fc_expr;

				if (fc_sublink->subLinkType == EXPR_SUBLINK ||
					fc_sublink->subLinkType == ARRAY_SUBLINK)
				{
					/* 获取子查询第一个目标列的 typmod */
					Query	   *fc_qtree = (Query *) fc_sublink->subselect;
					TargetEntry *fc_tent;

					if (!fc_qtree || !IsA(fc_qtree, Query))
						elog(ERROR, "cannot get type for untransformed sublink");
					fc_tent = linitial_node(TargetEntry, fc_qtree->targetList);
					Assert(!fc_tent->resjunk);
					return exprTypmod((Node *) fc_tent->expr);
					/* 请注意，我们不需要关心它是否是数组 */
				}
				/* 否则，结果是 RECORD 或 BOOLEAN，typmod 为 -1 */
			}
			break;
		case T_SubPlan:
			{
				const SubPlan *fc_subplan = (const SubPlan *) fc_expr;

				if (fc_subplan->subLinkType == EXPR_SUBLINK ||
					fc_subplan->subLinkType == ARRAY_SUBLINK)
				{
					/* 获取子查询第一个目标列的 typmod */
					/* 请注意，我们不需要关心它是否是数组 */
					return fc_subplan->firstColTypmod;
				}
				/* 否则，结果是 RECORD 或 BOOLEAN，typmod 为 -1 */
			}
			break;
		case T_AlternativeSubPlan:
			{
				const AlternativeSubPlan *fc_asplan = (const AlternativeSubPlan *) fc_expr;

				/* 所有子计划应返回相同的结果 */
				return exprTypmod((Node *) linitial(fc_asplan->subplans));
			}
			break;
		case T_FieldSelect:
			return ((const FieldSelect *) fc_expr)->resulttypmod;
		case T_RelabelType:
			return ((const RelabelType *) fc_expr)->resulttypmod;
		case T_ArrayCoerceExpr:
			return ((const ArrayCoerceExpr *) fc_expr)->resulttypmod;
		case T_CollateExpr:
			return exprTypmod((Node *) ((const CollateExpr *) fc_expr)->arg);
		case T_CaseExpr:
			{
				/*
				 * 如果所有的备选方案在类型/typmod 上都一致，则返回该
				 * typmod，否则使用 -1
				 */
				const CaseExpr *fc_cexpr = (const CaseExpr *) fc_expr;
				Oid			fc_casetype = fc_cexpr->casetype;
				int32		fc_typmod;
				ListCell   *fc_arg;

				if (!fc_cexpr->defresult)
					return -1;
				if (exprType((Node *) fc_cexpr->defresult) != fc_casetype)
					return -1;
				fc_typmod = exprTypmod((Node *) fc_cexpr->defresult);
				if (fc_typmod < 0)
					return -1;	/* 没有必要再更努力了 */
				foreach(fc_arg, fc_cexpr->args)
				{
					CaseWhen   *fc_w = lfirst_node(CaseWhen, fc_arg);

					if (exprType((Node *) fc_w->result) != fc_casetype)
						return -1;
					if (exprTypmod((Node *) fc_w->result) != fc_typmod)
						return -1;
				}
				return fc_typmod;
			}
			break;
		case T_CaseTestExpr:
			return ((const CaseTestExpr *) fc_expr)->typeMod;
		case T_ArrayExpr:
			{
				/*
				 * 如果所有元素在类型/typmod 上一致，则返回该
				 * typmod，否则使用 -1
				 */
				const ArrayExpr *fc_arrayexpr = (const ArrayExpr *) fc_expr;
				Oid			fc_commontype;
				int32		fc_typmod;
				ListCell   *fc_elem;

				if (fc_arrayexpr->elements == NIL)
					return -1;
				fc_typmod = exprTypmod((Node *) linitial(fc_arrayexpr->elements));
				if (fc_typmod < 0)
					return -1;	/* 没有必要再更努力了 */
				if (fc_arrayexpr->multidims)
					fc_commontype = fc_arrayexpr->array_typeid;
				else
					fc_commontype = fc_arrayexpr->element_typeid;
				foreach(fc_elem, fc_arrayexpr->elements)
				{
					Node	   *fc_e = (Node *) lfirst(fc_elem);

					if (exprType(fc_e) != fc_commontype)
						return -1;
					if (exprTypmod(fc_e) != fc_typmod)
						return -1;
				}
				return fc_typmod;
			}
			break;
		case T_CoalesceExpr:
			{
				/*
				 * 如果所有的备选方案在类型/typmod 上都一致，则返回该
				 * typmod，否则使用 -1
				 */
				const CoalesceExpr *fc_cexpr = (const CoalesceExpr *) fc_expr;
				Oid			fc_coalescetype = fc_cexpr->coalescetype;
				int32		fc_typmod;
				ListCell   *fc_arg;

				if (exprType((Node *) linitial(fc_cexpr->args)) != fc_coalescetype)
					return -1;
				fc_typmod = exprTypmod((Node *) linitial(fc_cexpr->args));
				if (fc_typmod < 0)
					return -1;	/* 没有必要再更努力了 */
				for_each_from(fc_arg, fc_cexpr->args, 1)
				{
					Node	   *fc_e = (Node *) lfirst(fc_arg);

					if (exprType(fc_e) != fc_coalescetype)
						return -1;
					if (exprTypmod(fc_e) != fc_typmod)
						return -1;
				}
				return fc_typmod;
			}
			break;
		case T_MinMaxExpr:
			{
				/*
				 * 如果所有的备选方案在类型/typmod 上都一致，则返回该
				 * typmod，否则使用 -1
				 */
				const MinMaxExpr *fc_mexpr = (const MinMaxExpr *) fc_expr;
				Oid			fc_minmaxtype = fc_mexpr->minmaxtype;
				int32		fc_typmod;
				ListCell   *fc_arg;

				if (exprType((Node *) linitial(fc_mexpr->args)) != fc_minmaxtype)
					return -1;
				fc_typmod = exprTypmod((Node *) linitial(fc_mexpr->args));
				if (fc_typmod < 0)
					return -1;	/* 没有必要再更努力了 */
				for_each_from(fc_arg, fc_mexpr->args, 1)
				{
					Node	   *fc_e = (Node *) lfirst(fc_arg);

					if (exprType(fc_e) != fc_minmaxtype)
						return -1;
					if (exprTypmod(fc_e) != fc_typmod)
						return -1;
				}
				return fc_typmod;
			}
			break;
		case T_SQLValueFunction:
			return ((const SQLValueFunction *) fc_expr)->typmod;
		case T_CoerceToDomain:
			return ((const CoerceToDomain *) fc_expr)->resulttypmod;
		case T_CoerceToDomainValue:
			return ((const CoerceToDomainValue *) fc_expr)->typeMod;
		case T_SetToDefault:
			return ((const SetToDefault *) fc_expr)->typeMod;
		case T_PlaceHolderVar:
			return exprTypmod((Node *) ((const PlaceHolderVar *) fc_expr)->phexpr);
		default:
			break;
	}
	return -1;
}

/*
 * exprIsLengthCoercion
 *		检测表达式树是否为数据类型的
 *		typmod-强制函数的应用。可选地提取结果的 typmod。
 *
 * 如果 coercedTypmod 不是 NULL，该 typmod 在这里存储，如果表达式
 * 是长度强制函数，否则 -1 将存储在这里。
 *
 * 请注意，联合类型和长度强制将被此例程视为长度强制。
 */
bool exprIsLengthCoercion(const Node *fc_expr, int32 *fc_coercedTypmod)
{
	if (fc_coercedTypmod != NULL)
		*fc_coercedTypmod = -1;	/* 失败时的默认结果 */

	/*
	 * 标量类型的长度强制是 FuncExprs，数组类型的长度强制
	 * 是 ArrayCoerceExprs
	 */
	if (fc_expr && IsA(fc_expr, FuncExpr))
	{
		const FuncExpr *fc_func = (const FuncExpr *) fc_expr;
		int			fc_nargs;
		Const	   *fc_second_arg;

		/*
		 * 如果它不是来自强制上下文，则拒绝。
		 */
		if (fc_func->funcformat != COERCE_EXPLICIT_CAST &&
			fc_func->funcformat != COERCE_IMPLICIT_CAST)
			return false;

		/*
		 * 如果它不是带有第二个参数为 int4 常量的
		 * 具有两个或三个参数的函数，则它不能是来自长度强制
		 * （它必须是类型强制）。
		 */
		fc_nargs = list_length(fc_func->args);
		if (fc_nargs < 2 || fc_nargs > 3)
			return false;

		fc_second_arg = (Const *) lsecond(fc_func->args);
		if (!IsA(fc_second_arg, Const) ||
			fc_second_arg->consttype != INT4OID ||
			fc_second_arg->constisnull)
			return false;

		/*
		 * 好吧，确实是一个长度强制函数。
		 */
		if (fc_coercedTypmod != NULL)
			*fc_coercedTypmod = DatumGetInt32(fc_second_arg->constvalue);

		return true;
	}

	if (fc_expr && IsA(fc_expr, ArrayCoerceExpr))
	{
		const ArrayCoerceExpr *fc_acoerce = (const ArrayCoerceExpr *) fc_expr;

		/* 只有在存在非默认 typmod 时，才算作长度强制 */
		if (fc_acoerce->resulttypmod < 0)
			return false;

		/*
		 * 好吧，确实是一个长度强制表达式。
		 */
		if (fc_coercedTypmod != NULL)
			*fc_coercedTypmod = fc_acoerce->resulttypmod;

		return true;
	}

	return false;
}

/*
 * applyRelabelType
 *		如果需要，添加一个 RelabelType 节点，使表达式暴露
 *		指定的类型、typmod 和排序规则。
 *
 * 这主要用于规划期间。因此，它必须
 * 维护 post-eval_const_expressions 不变式，即不允许
 * 相邻的 RelabelTypes，并且树是完全常量折叠的（因此，
 * 我们不能在 Const 顶部返回一个 RelabelType）。如果我们发现
 * 一个 Const，如果 "overwrite_ok" 为 true，我们将就地修改它；
 * 只有在调用者知道 Const 是新生成的情况下才应将其设为 true。
 */
Node * applyRelabelType(Node *fc_arg, Oid fc_rtype, int32 fc_rtypmod, Oid fc_rcollid,
				 CoercionForm fc_rformat, int fc_rlocation, bool fc_overwrite_ok)
{
	/*
	 * 如果我们发现堆叠的 RelabelTypes（例如，从 foo::int::oid），
	 * 我们可以丢弃除顶部之外的所有并且必须这样做，以确保语义
	 * 等效的表达式是相等的。
	 */
	while (fc_arg && IsA(fc_arg, RelabelType))
		fc_arg = (Node *) ((RelabelType *) fc_arg)->arg;

	if (fc_arg && IsA(fc_arg, Const))
	{
		/* 直接修改 Const 以保持常量平坦性。 */
		Const	   *fc_con = (Const *) fc_arg;

		if (!fc_overwrite_ok)
			fc_con = copyObject(fc_con);
		fc_con->consttype = fc_rtype;
		fc_con->consttypmod = fc_rtypmod;
		fc_con->constcollid = fc_rcollid;
		/* 我们保留 Const 的原始位置。 */
		return (Node *) fc_con;
	}
	else if (exprType(fc_arg) == fc_rtype &&
			 exprTypmod(fc_arg) == fc_rtypmod &&
			 exprCollation(fc_arg) == fc_rcollid)
	{
		/* 有时我们发现一组嵌套的重标识最终什么也没表示。 */
		return fc_arg;
	}
	else
	{
		/* 不行，必须有一个 RelabelType。 */
		RelabelType *fc_newrelabel = makeNode(RelabelType);

		fc_newrelabel->arg = (Expr *) fc_arg;
		fc_newrelabel->resulttype = fc_rtype;
		fc_newrelabel->resulttypmod = fc_rtypmod;
		fc_newrelabel->resultcollid = fc_rcollid;
		fc_newrelabel->relabelformat = fc_rformat;
		fc_newrelabel->location = fc_rlocation;
		return (Node *) fc_newrelabel;
	}
}

/*
 * relabel_to_typmod
 *		添加一个 RelabelType 节点，仅更改表达式的 typmod。
 *
 * 用于 applyRelabelType 的常用便利函数。
 */
Node * relabel_to_typmod(Node *fc_expr, int32 fc_typmod)
{
	return applyRelabelType(fc_expr, exprType(fc_expr), fc_typmod, exprCollation(fc_expr),
							COERCE_EXPLICIT_CAST, -1, false);
}

/*
 * strip_implicit_coercions: 在树的顶层移除隐式强制
 *
 * 这不会修改或复制输入表达式树，只返回一个指向合适位置的指针。
 *
 * 注意：我们在这里没有任何有用的 RowExpr，所以即使它标记为隐式强制，
 * 也只是返回它未改变的状态。
 */
Node * strip_implicit_coercions(Node *fc_node)
{
	if (fc_node == NULL)
		return NULL;
	if (IsA(fc_node, FuncExpr))
	{
		FuncExpr   *fc_f = (FuncExpr *) fc_node;

		if (fc_f->funcformat == COERCE_IMPLICIT_CAST)
			return strip_implicit_coercions(linitial(fc_f->args));
	}
	else if (IsA(fc_node, RelabelType))
	{
		RelabelType *fc_r = (RelabelType *) fc_node;

		if (fc_r->relabelformat == COERCE_IMPLICIT_CAST)
			return strip_implicit_coercions((Node *) fc_r->arg);
	}
	else if (IsA(fc_node, CoerceViaIO))
	{
		CoerceViaIO *fc_c = (CoerceViaIO *) fc_node;

		if (fc_c->coerceformat == COERCE_IMPLICIT_CAST)
			return strip_implicit_coercions((Node *) fc_c->arg);
	}
	else if (IsA(fc_node, ArrayCoerceExpr))
	{
		ArrayCoerceExpr *fc_c = (ArrayCoerceExpr *) fc_node;

		if (fc_c->coerceformat == COERCE_IMPLICIT_CAST)
			return strip_implicit_coercions((Node *) fc_c->arg);
	}
	else if (IsA(fc_node, ConvertRowtypeExpr))
	{
		ConvertRowtypeExpr *fc_c = (ConvertRowtypeExpr *) fc_node;

		if (fc_c->convertformat == COERCE_IMPLICIT_CAST)
			return strip_implicit_coercions((Node *) fc_c->arg);
	}
	else if (IsA(fc_node, CoerceToDomain))
	{
		CoerceToDomain *fc_c = (CoerceToDomain *) fc_node;

		if (fc_c->coercionformat == COERCE_IMPLICIT_CAST)
			return strip_implicit_coercions((Node *) fc_c->arg);
	}
	return fc_node;
}

/*
 * expression_returns_set
 *	  测试表达式是否返回集合结果。
 *
 * 因为我们使用 expression_tree_walker()，这也可以适用于
 * 整个目标列表；如果任何一个目标列表项返回集合，它将返回 true。
 */
bool expression_returns_set(Node *fc_clause)
{
	return fc_expression_returns_set_walker(fc_clause, NULL);
}

static bool fc_expression_returns_set_walker(Node *fc_node, void *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, FuncExpr))
	{
		FuncExpr   *fc_expr = (FuncExpr *) fc_node;

		if (fc_expr->funcretset)
			return true;
		/* 否则继续检查参数 */
	}
	if (IsA(fc_node, OpExpr))
	{
		OpExpr	   *fc_expr = (OpExpr *) fc_node;

		if (fc_expr->opretset)
			return true;
		/* 否则继续检查参数 */
	}

	/*
	 * 如果你添加任何更多返回集合的情况，还要修复
	 * clauses.c 中的 expression_returns_set_rows() 和
	 * tlist.c 中的 IS_SRF_CALL()。
	 */

	/* 避免为一些解析器检查不返回集合的情况进行递归 */
	if (IsA(fc_node, Aggref))
		return false;
	if (IsA(fc_node, GroupingFunc))
		return false;
	if (IsA(fc_node, WindowFunc))
		return false;

	return expression_tree_walker(fc_node, fc_expression_returns_set_walker,
								  fc_context);
}


/*
 *	exprCollation -
 *	  返回表达式结果的排序规则的 Oid。
 *
 * 注意：可以调用函数的表达式节点通常具有一个
 * "inputcollid" 字段，这就是函数应作为排序规则使用的内容。
 * 这是节点输入的解析后的通用排序规则。通常，但并不总是与结果排序规则相同；
 * 特别是，如果函数从可排序输入产生不可排序的结果类型或反之亦然，则两者不同。
 */
Oid exprCollation(const Node *fc_expr)
{
	Oid			fc_coll;

	if (!fc_expr)
		return InvalidOid;

	switch (nodeTag(fc_expr))
	{
		case T_Var:
			fc_coll = ((const Var *) fc_expr)->varcollid;
			break;
		case T_Const:
			fc_coll = ((const Const *) fc_expr)->constcollid;
			break;
		case T_Param:
			fc_coll = ((const Param *) fc_expr)->paramcollid;
			break;
		case T_Aggref:
			fc_coll = ((const Aggref *) fc_expr)->aggcollid;
			break;
		case T_GroupingFunc:
			fc_coll = InvalidOid;
			break;
		case T_WindowFunc:
			fc_coll = ((const WindowFunc *) fc_expr)->wincollid;
			break;
		case T_SubscriptingRef:
			fc_coll = ((const SubscriptingRef *) fc_expr)->refcollid;
			break;
		case T_FuncExpr:
			fc_coll = ((const FuncExpr *) fc_expr)->funccollid;
			break;
		case T_NamedArgExpr:
			fc_coll = exprCollation((Node *) ((const NamedArgExpr *) fc_expr)->arg);
			break;
		case T_OpExpr:
			fc_coll = ((const OpExpr *) fc_expr)->opcollid;
			break;
		case T_DistinctExpr:
			fc_coll = ((const DistinctExpr *) fc_expr)->opcollid;
			break;
		case T_NullIfExpr:
			fc_coll = ((const NullIfExpr *) fc_expr)->opcollid;
			break;
		case T_ScalarArrayOpExpr:
			/* ScalarArrayOpExpr的结果是布尔值... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_BoolExpr:
			/* BoolExpr的结果是布尔值... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_SubLink:
			{
				const SubLink *fc_sublink = (const SubLink *) fc_expr;

				if (fc_sublink->subLinkType == EXPR_SUBLINK ||
					fc_sublink->subLinkType == ARRAY_SUBLINK)
				{
					/* 获取子查询第一个目标列的排序规则 */
					Query	   *fc_qtree = (Query *) fc_sublink->subselect;
					TargetEntry *fc_tent;

					if (!fc_qtree || !IsA(fc_qtree, Query))
						elog(ERROR, "cannot get collation for untransformed sublink");
					fc_tent = linitial_node(TargetEntry, fc_qtree->targetList);
					Assert(!fc_tent->resjunk);
					fc_coll = exprCollation((Node *) fc_tent->expr);
					/* 如果转换为数组，排序规则不会改变 */
				}
				else
				{
					/* 否则，SubLink的结果是RECORD或BOOLEAN */
					fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
				}
			}
			break;
		case T_SubPlan:
			{
				const SubPlan *fc_subplan = (const SubPlan *) fc_expr;

				if (fc_subplan->subLinkType == EXPR_SUBLINK ||
					fc_subplan->subLinkType == ARRAY_SUBLINK)
				{
					/* 获取子查询第一个目标列的排序规则 */
					fc_coll = fc_subplan->firstColCollation;
					/* 如果转换为数组，排序规则不会改变 */
				}
				else
				{
					/* 否则，SubPlan的结果是RECORD或BOOLEAN */
					fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
				}
			}
			break;
		case T_AlternativeSubPlan:
			{
				const AlternativeSubPlan *fc_asplan = (const AlternativeSubPlan *) fc_expr;

				/* 所有子计划应返回相同的结果 */
				fc_coll = exprCollation((Node *) linitial(fc_asplan->subplans));
			}
			break;
		case T_FieldSelect:
			fc_coll = ((const FieldSelect *) fc_expr)->resultcollid;
			break;
		case T_FieldStore:
			/* FieldStore的结果是复合... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_RelabelType:
			fc_coll = ((const RelabelType *) fc_expr)->resultcollid;
			break;
		case T_CoerceViaIO:
			fc_coll = ((const CoerceViaIO *) fc_expr)->resultcollid;
			break;
		case T_ArrayCoerceExpr:
			fc_coll = ((const ArrayCoerceExpr *) fc_expr)->resultcollid;
			break;
		case T_ConvertRowtypeExpr:
			/* ConvertRowtypeExpr的结果是复合... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_CollateExpr:
			fc_coll = ((const CollateExpr *) fc_expr)->collOid;
			break;
		case T_CaseExpr:
			fc_coll = ((const CaseExpr *) fc_expr)->casecollid;
			break;
		case T_CaseTestExpr:
			fc_coll = ((const CaseTestExpr *) fc_expr)->collation;
			break;
		case T_ArrayExpr:
			fc_coll = ((const ArrayExpr *) fc_expr)->array_collid;
			break;
		case T_RowExpr:
			/* RowExpr的结果是复合... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_RowCompareExpr:
			/* RowCompareExpr的结果是布尔值... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_CoalesceExpr:
			fc_coll = ((const CoalesceExpr *) fc_expr)->coalescecollid;
			break;
		case T_MinMaxExpr:
			fc_coll = ((const MinMaxExpr *) fc_expr)->minmaxcollid;
			break;
		case T_SQLValueFunction:
			/* 返回NAME或非排序规则类型 */
			if (((const SQLValueFunction *) fc_expr)->type == NAMEOID)
				fc_coll = C_COLLATION_OID;
			else
				fc_coll = InvalidOid;
			break;
		case T_XmlExpr:

			/*
			 * XMLSERIALIZE从非排序规则的输入返回文本，因此其
			 * 排序规则始终是默认的。其他情况返回布尔值或
			 * XML，这些都是非排序规则。
			 */
			if (((const XmlExpr *) fc_expr)->op == IS_XMLSERIALIZE)
				fc_coll = DEFAULT_COLLATION_OID;
			else
				fc_coll = InvalidOid;
			break;
		case T_NullTest:
			/* NullTest的结果是布尔值... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_BooleanTest:
			/* BooleanTest的结果是布尔值... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_CoerceToDomain:
			fc_coll = ((const CoerceToDomain *) fc_expr)->resultcollid;
			break;
		case T_CoerceToDomainValue:
			fc_coll = ((const CoerceToDomainValue *) fc_expr)->collation;
			break;
		case T_SetToDefault:
			fc_coll = ((const SetToDefault *) fc_expr)->collation;
			break;
		case T_CurrentOfExpr:
			/* CurrentOfExpr的结果是布尔值... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_NextValueExpr:
			/* NextValueExpr的结果是整数类型... */
			fc_coll = InvalidOid;	/* ...所以它没有排序规则 */
			break;
		case T_InferenceElem:
			fc_coll = exprCollation((Node *) ((const InferenceElem *) fc_expr)->expr);
			break;
		case T_PlaceHolderVar:
			fc_coll = exprCollation((Node *) ((const PlaceHolderVar *) fc_expr)->phexpr);
			break;
		default:
			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(fc_expr));
			fc_coll = InvalidOid;	/* 保持编译器安静 */
			break;
	}
	return fc_coll;
}

/*
 *	exprInputCollation -
 *	  返回函数应该使用的排序规则的Oid（如果可用）。
 *
 * 如果节点类型不存储此信息，则结果为InvalidOid。
 */
Oid exprInputCollation(const Node *fc_expr)
{
	Oid			fc_coll;

	if (!fc_expr)
		return InvalidOid;

	switch (nodeTag(fc_expr))
	{
		case T_Aggref:
			fc_coll = ((const Aggref *) fc_expr)->inputcollid;
			break;
		case T_WindowFunc:
			fc_coll = ((const WindowFunc *) fc_expr)->inputcollid;
			break;
		case T_FuncExpr:
			fc_coll = ((const FuncExpr *) fc_expr)->inputcollid;
			break;
		case T_OpExpr:
			fc_coll = ((const OpExpr *) fc_expr)->inputcollid;
			break;
		case T_DistinctExpr:
			fc_coll = ((const DistinctExpr *) fc_expr)->inputcollid;
			break;
		case T_NullIfExpr:
			fc_coll = ((const NullIfExpr *) fc_expr)->inputcollid;
			break;
		case T_ScalarArrayOpExpr:
			fc_coll = ((const ScalarArrayOpExpr *) fc_expr)->inputcollid;
			break;
		case T_MinMaxExpr:
			fc_coll = ((const MinMaxExpr *) fc_expr)->inputcollid;
			break;
		default:
			fc_coll = InvalidOid;
			break;
	}
	return fc_coll;
}

/*
 *	exprSetCollation -
 *	  将排序规则信息分配给表达式树节点。
 *
 * 注意：由于这仅在解析分析期间使用，因此我们不需要
 * 担心子计划或PlaceHolderVars。
 */
void exprSetCollation(Node *fc_expr, Oid fc_collation)
{
	switch (nodeTag(fc_expr))
	{
		case T_Var:
			((Var *) fc_expr)->varcollid = fc_collation;
			break;
		case T_Const:
			((Const *) fc_expr)->constcollid = fc_collation;
			break;
		case T_Param:
			((Param *) fc_expr)->paramcollid = fc_collation;
			break;
		case T_Aggref:
			((Aggref *) fc_expr)->aggcollid = fc_collation;
			break;
		case T_GroupingFunc:
			Assert(!OidIsValid(fc_collation));
			break;
		case T_WindowFunc:
			((WindowFunc *) fc_expr)->wincollid = fc_collation;
			break;
		case T_SubscriptingRef:
			((SubscriptingRef *) fc_expr)->refcollid = fc_collation;
			break;
		case T_FuncExpr:
			((FuncExpr *) fc_expr)->funccollid = fc_collation;
			break;
		case T_NamedArgExpr:
			Assert(fc_collation == exprCollation((Node *) ((NamedArgExpr *) fc_expr)->arg));
			break;
		case T_OpExpr:
			((OpExpr *) fc_expr)->opcollid = fc_collation;
			break;
		case T_DistinctExpr:
			((DistinctExpr *) fc_expr)->opcollid = fc_collation;
			break;
		case T_NullIfExpr:
			((NullIfExpr *) fc_expr)->opcollid = fc_collation;
			break;
		case T_ScalarArrayOpExpr:
			/* ScalarArrayOpExpr的结果是布尔值... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_BoolExpr:
			/* BoolExpr的结果是布尔值... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_SubLink:
#ifdef USE_ASSERT_CHECKING
			{
				SubLink    *fc_sublink = (SubLink *) fc_expr;

				if (fc_sublink->subLinkType == EXPR_SUBLINK ||
					fc_sublink->subLinkType == ARRAY_SUBLINK)
				{
					/* 获取子查询第一个目标列的排序规则 */
					Query	   *fc_qtree = (Query *) fc_sublink->subselect;
					TargetEntry *fc_tent;

					if (!fc_qtree || !IsA(fc_qtree, Query))
						elog(ERROR, "cannot set collation for untransformed sublink");
					fc_tent = linitial_node(TargetEntry, fc_qtree->targetList);
					Assert(!fc_tent->resjunk);
					Assert(fc_collation == exprCollation((Node *) fc_tent->expr));
				}
				else
				{
					/* 否则，结果为RECORD或BOOLEAN */
					Assert(!OidIsValid(fc_collation));
				}
			}
#endif							/* USE_ASSERT_CHECKING */
			break;
		case T_FieldSelect:
			((FieldSelect *) fc_expr)->resultcollid = fc_collation;
			break;
		case T_FieldStore:
			/* FieldStore的结果是复合... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_RelabelType:
			((RelabelType *) fc_expr)->resultcollid = fc_collation;
			break;
		case T_CoerceViaIO:
			((CoerceViaIO *) fc_expr)->resultcollid = fc_collation;
			break;
		case T_ArrayCoerceExpr:
			((ArrayCoerceExpr *) fc_expr)->resultcollid = fc_collation;
			break;
		case T_ConvertRowtypeExpr:
			/* ConvertRowtypeExpr的结果是复合... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_CaseExpr:
			((CaseExpr *) fc_expr)->casecollid = fc_collation;
			break;
		case T_ArrayExpr:
			((ArrayExpr *) fc_expr)->array_collid = fc_collation;
			break;
		case T_RowExpr:
			/* RowExpr的结果是复合... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_RowCompareExpr:
			/* RowCompareExpr的结果是布尔值... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_CoalesceExpr:
			((CoalesceExpr *) fc_expr)->coalescecollid = fc_collation;
			break;
		case T_MinMaxExpr:
			((MinMaxExpr *) fc_expr)->minmaxcollid = fc_collation;
			break;
		case T_SQLValueFunction:
			Assert((((SQLValueFunction *) fc_expr)->type == NAMEOID) ?
				   (fc_collation == C_COLLATION_OID) :
				   (fc_collation == InvalidOid));
			break;
		case T_XmlExpr:
			Assert((((XmlExpr *) fc_expr)->op == IS_XMLSERIALIZE) ?
				   (fc_collation == DEFAULT_COLLATION_OID) :
				   (fc_collation == InvalidOid));
			break;
		case T_NullTest:
			/* NullTest的结果是布尔值... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_BooleanTest:
			/* BooleanTest的结果是布尔值... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_CoerceToDomain:
			((CoerceToDomain *) fc_expr)->resultcollid = fc_collation;
			break;
		case T_CoerceToDomainValue:
			((CoerceToDomainValue *) fc_expr)->collation = fc_collation;
			break;
		case T_SetToDefault:
			((SetToDefault *) fc_expr)->collation = fc_collation;
			break;
		case T_CurrentOfExpr:
			/* CurrentOfExpr的结果是布尔值... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		case T_NextValueExpr:
			/* NextValueExpr的结果是整数类型... */
			Assert(!OidIsValid(fc_collation)); /* ...所以从不设置排序规则 */
			break;
		default:
			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(fc_expr));
			break;
	}
}

/*
 *	exprSetInputCollation -
 *	  将输入排序规则信息分配给表达式树节点。
 *
 * 对于不存储其输入排序规则的节点类型，这是一项无操作。
 * 注意我们省略RowCompareExpr，因为它需要特殊处理，因为它
 * 包含多个输入排序规则OID。
 */
void exprSetInputCollation(Node *fc_expr, Oid fc_inputcollation)
{
	switch (nodeTag(fc_expr))
	{
		case T_Aggref:
			((Aggref *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		case T_WindowFunc:
			((WindowFunc *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		case T_FuncExpr:
			((FuncExpr *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		case T_OpExpr:
			((OpExpr *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		case T_DistinctExpr:
			((DistinctExpr *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		case T_NullIfExpr:
			((NullIfExpr *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		case T_ScalarArrayOpExpr:
			((ScalarArrayOpExpr *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		case T_MinMaxExpr:
			((MinMaxExpr *) fc_expr)->inputcollid = fc_inputcollation;
			break;
		default:
			break;
	}
}


/*
 *	exprLocation -
 *	  返回表达式树的解析位置，以便进行错误报告
 *
 * 如果无法确定位置，则返回-1。
 *
 * 对于大于单个标记的表达式，这里打算返回
 * 表达式最左侧标记的位置，而不一定是
 * 最上面的节点的位置信息。例如，一个OpExpr的位置信息
 * 字段将指向操作符名称，但如果它不是一个前缀操作符
 * 则我们应该返回左操作数的位置。
 * 原因是我们希望引用整个表达式，而不仅仅
 * 是那个操作符，指向其开始似乎是最自然的方式。
 *
 * 这个位置并不完美——例如，由于语法没有
 * 明确表示括号在解析树中，给定写成的
 * "(a + b) * c"，我们将指向"a"而不是"("。
 * 但对于错误报告目的来说，这应该足够好。
 *
 * 你可能会认为这段代码过于通用，例如为什么要检查
 * FuncExpr节点的操作数，函数名称可以期望在它们的左侧？
 * 这有几个原因。语法有时会构建与用户输入不完全相同的表达式；
 * 例如，x IS NOT BETWEEN ...变成了一个NOT表达式，其关键字
 * 指针位于最左侧参数的右侧。此外，解析分析隐式插入的节点
 * （例如用于隐式强制转换的FuncExprs）将具有位置-1，因此我们可以在树中有已知和未知位置的不寻常组合。
 */
int exprLocation(const Node *fc_expr)
{
	int			fc_loc;

	if (fc_expr == NULL)
		return -1;
	switch (nodeTag(fc_expr))
	{
		case T_RangeVar:
			fc_loc = ((const RangeVar *) fc_expr)->location;
			break;
		case T_TableFunc:
			fc_loc = ((const TableFunc *) fc_expr)->location;
			break;
		case T_Var:
			fc_loc = ((const Var *) fc_expr)->location;
			break;
		case T_Const:
			fc_loc = ((const Const *) fc_expr)->location;
			break;
		case T_Param:
			fc_loc = ((const Param *) fc_expr)->location;
			break;
		case T_Aggref:
			/* 函数名称应该始终是第一项 */
			fc_loc = ((const Aggref *) fc_expr)->location;
			break;
		case T_GroupingFunc:
			fc_loc = ((const GroupingFunc *) fc_expr)->location;
			break;
		case T_WindowFunc:
			/* 函数名称应该始终是第一项 */
			fc_loc = ((const WindowFunc *) fc_expr)->location;
			break;
		case T_SubscriptingRef:
			/* 仅使用容器参数的位置 */
			fc_loc = exprLocation((Node *) ((const SubscriptingRef *) fc_expr)->refexpr);
			break;
		case T_FuncExpr:
			{
				const FuncExpr *fc_fexpr = (const FuncExpr *) fc_expr;

				/* 考虑函数名称和最左侧参数 */
				fc_loc = fc_leftmostLoc(fc_fexpr->location,
								  exprLocation((Node *) fc_fexpr->args));
			}
			break;
		case T_NamedArgExpr:
			{
				const NamedArgExpr *fc_na = (const NamedArgExpr *) fc_expr;

				/* 考虑参数名称和值 */
				fc_loc = fc_leftmostLoc(fc_na->location,
								  exprLocation((Node *) fc_na->arg));
			}
			break;
		case T_OpExpr:
		case T_DistinctExpr:	/* 相当于OpExpr的结构 */
		case T_NullIfExpr:		/* 相当于OpExpr的结构 */
			{
				const OpExpr *fc_opexpr = (const OpExpr *) fc_expr;

				/* 考虑操作符名称和最左侧参数 */
				fc_loc = fc_leftmostLoc(fc_opexpr->location,
								  exprLocation((Node *) fc_opexpr->args));
			}
			break;
		case T_ScalarArrayOpExpr:
			{
				const ScalarArrayOpExpr *fc_saopexpr = (const ScalarArrayOpExpr *) fc_expr;

				/* 考虑操作符名称和最左侧参数 */
				fc_loc = fc_leftmostLoc(fc_saopexpr->location,
								  exprLocation((Node *) fc_saopexpr->args));
			}
			break;
		case T_BoolExpr:
			{
				const BoolExpr *fc_bexpr = (const BoolExpr *) fc_expr;

				/*
				 * 与以上相同，以处理NOT或AND/OR。我们不能
				 * 对NOT进行特殊处理，因为它用于
				 * 像IS NOT BETWEEN这样的情况。
				 */
				fc_loc = fc_leftmostLoc(fc_bexpr->location,
								  exprLocation((Node *) fc_bexpr->args));
			}
			break;
		case T_SubLink:
			{
				const SubLink *fc_sublink = (const SubLink *) fc_expr;

				/* 检查测试表达式（如有）以及操作符/关键字 */
				fc_loc = fc_leftmostLoc(exprLocation(fc_sublink->testexpr),
								  fc_sublink->location);
			}
			break;
		case T_FieldSelect:
			/* 仅使用参数的位置 */
			fc_loc = exprLocation((Node *) ((const FieldSelect *) fc_expr)->arg);
			break;
		case T_FieldStore:
			/* 仅使用参数的位置 */
			fc_loc = exprLocation((Node *) ((const FieldStore *) fc_expr)->arg);
			break;
		case T_RelabelType:
			{
				const RelabelType *fc_rexpr = (const RelabelType *) fc_expr;

				/* 以上类似 */
				fc_loc = fc_leftmostLoc(fc_rexpr->location,
								  exprLocation((Node *) fc_rexpr->arg));
			}
			break;
		case T_CoerceViaIO:
			{
				const CoerceViaIO *fc_cexpr = (const CoerceViaIO *) fc_expr;

				/* 以上类似 */
				fc_loc = fc_leftmostLoc(fc_cexpr->location,
								  exprLocation((Node *) fc_cexpr->arg));
			}
			break;
		case T_ArrayCoerceExpr:
			{
				const ArrayCoerceExpr *fc_cexpr = (const ArrayCoerceExpr *) fc_expr;

				/* 以上类似 */
				fc_loc = fc_leftmostLoc(fc_cexpr->location,
								  exprLocation((Node *) fc_cexpr->arg));
			}
			break;
		case T_ConvertRowtypeExpr:
			{
				const ConvertRowtypeExpr *fc_cexpr = (const ConvertRowtypeExpr *) fc_expr;

				/* 以上类似 */
				fc_loc = fc_leftmostLoc(fc_cexpr->location,
								  exprLocation((Node *) fc_cexpr->arg));
			}
			break;
		case T_CollateExpr:
			/* 仅使用参数的位置 */
			fc_loc = exprLocation((Node *) ((const CollateExpr *) fc_expr)->arg);
			break;
		case T_CaseExpr:
			/* CASE 关键字应该始终是第一个 */
			fc_loc = ((const CaseExpr *) fc_expr)->location;
			break;
		case T_CaseWhen:
			/* WHEN 关键字应该始终是第一个 */
			fc_loc = ((const CaseWhen *) fc_expr)->location;
			break;
		case T_ArrayExpr:
			/* 位置指向 ARRAY 或 [，必须是最左侧 */
			fc_loc = ((const ArrayExpr *) fc_expr)->location;
			break;
		case T_RowExpr:
			/* 位置指向 ROW 或 (，必须是最左侧 */
			fc_loc = ((const RowExpr *) fc_expr)->location;
			break;
		case T_RowCompareExpr:
			/* 仅使用最左侧参数的位置 */
			fc_loc = exprLocation((Node *) ((const RowCompareExpr *) fc_expr)->largs);
			break;
		case T_CoalesceExpr:
			/* COALESCE 关键字应该始终是第一个 */
			fc_loc = ((const CoalesceExpr *) fc_expr)->location;
			break;
		case T_MinMaxExpr:
			/* GREATEST/LEAST 关键字应该始终是第一个 */
			fc_loc = ((const MinMaxExpr *) fc_expr)->location;
			break;
		case T_SQLValueFunction:
			/* 函数关键字应该始终是第一个 */
			fc_loc = ((const SQLValueFunction *) fc_expr)->location;
			break;
		case T_XmlExpr:
			{
				const XmlExpr *fc_xexpr = (const XmlExpr *) fc_expr;

				/* 考虑函数名称和最左侧参数 */
				fc_loc = fc_leftmostLoc(fc_xexpr->location,
								  exprLocation((Node *) fc_xexpr->args));
			}
			break;
		case T_NullTest:
			{
				const NullTest *fc_nexpr = (const NullTest *) fc_expr;

				/* 以上类似 */
				fc_loc = fc_leftmostLoc(fc_nexpr->location,
								  exprLocation((Node *) fc_nexpr->arg));
			}
			break;
		case T_BooleanTest:
			{
				const BooleanTest *fc_bexpr = (const BooleanTest *) fc_expr;

				/* 以上类似 */
				fc_loc = fc_leftmostLoc(fc_bexpr->location,
								  exprLocation((Node *) fc_bexpr->arg));
			}
			break;
		case T_CoerceToDomain:
			{
				const CoerceToDomain *fc_cexpr = (const CoerceToDomain *) fc_expr;

				/* 以上类似 */
				fc_loc = fc_leftmostLoc(fc_cexpr->location,
								  exprLocation((Node *) fc_cexpr->arg));
			}
			break;
		case T_CoerceToDomainValue:
			fc_loc = ((const CoerceToDomainValue *) fc_expr)->location;
			break;
		case T_SetToDefault:
			fc_loc = ((const SetToDefault *) fc_expr)->location;
			break;
		case T_TargetEntry:
			/* 仅使用参数的位置 */
			fc_loc = exprLocation((Node *) ((const TargetEntry *) fc_expr)->expr);
			break;
		case T_IntoClause:
			/* 使用包含的 RangeVar 的位置 --- 足够接近 */
			fc_loc = exprLocation((Node *) ((const IntoClause *) fc_expr)->rel);
			break;
		case T_List:
			{
				/* 报告第一个具有位置的列表成员的位置 */
				ListCell   *fc_lc;

				fc_loc = -1;		/* 仅为了抑制编译器警告 */
				foreach(fc_lc, (const List *) fc_expr)
				{
					fc_loc = exprLocation((Node *) lfirst(fc_lc));
					if (fc_loc >= 0)
						break;
				}
			}
			break;
		case T_A_Expr:
			{
				const A_Expr *fc_aexpr = (const A_Expr *) fc_expr;

				/* 使用运算符或左操作数的最左侧（如果有） */
				/* 我们假设右操作数不能在运算符的左侧 */
				fc_loc = fc_leftmostLoc(fc_aexpr->location,
								  exprLocation(fc_aexpr->lexpr));
			}
			break;
		case T_ColumnRef:
			fc_loc = ((const ColumnRef *) fc_expr)->location;
			break;
		case T_ParamRef:
			fc_loc = ((const ParamRef *) fc_expr)->location;
			break;
		case T_A_Const:
			fc_loc = ((const A_Const *) fc_expr)->location;
			break;
		case T_FuncCall:
			{
				const FuncCall *fc_fc = (const FuncCall *) fc_expr;

				/* 考虑函数名称和最左侧参数 */
				/* （我们假设任何 ORDER BY 节点必须在名称的右侧） */
				fc_loc = fc_leftmostLoc(fc_fc->location,
								  exprLocation((Node *) fc_fc->args));
			}
			break;
		case T_A_ArrayExpr:
			/* 位置指向 ARRAY 或 [，必须是最左侧 */
			fc_loc = ((const A_ArrayExpr *) fc_expr)->location;
			break;
		case T_ResTarget:
			/* 我们不需要检查包含的表达式（如果有） */
			fc_loc = ((const ResTarget *) fc_expr)->location;
			break;
		case T_MultiAssignRef:
			fc_loc = exprLocation(((const MultiAssignRef *) fc_expr)->source);
			break;
		case T_TypeCast:
			{
				const TypeCast *fc_tc = (const TypeCast *) fc_expr;

				/* 
				 * 这可能表示 CAST()，::，或 TypeName 'literal'，因此
				 * 任何组件都可能是最左侧的。
				 */
				fc_loc = exprLocation(fc_tc->arg);
				fc_loc = fc_leftmostLoc(fc_loc, fc_tc->typeName->location);
				fc_loc = fc_leftmostLoc(fc_loc, fc_tc->location);
			}
			break;
		case T_CollateClause:
			/* 仅使用参数的位置 */
			fc_loc = exprLocation(((const CollateClause *) fc_expr)->arg);
			break;
		case T_SortBy:
			/* 仅使用参数的位置（忽略运算符，如果有） */
			fc_loc = exprLocation(((const SortBy *) fc_expr)->node);
			break;
		case T_WindowDef:
			fc_loc = ((const WindowDef *) fc_expr)->location;
			break;
		case T_RangeTableSample:
			fc_loc = ((const RangeTableSample *) fc_expr)->location;
			break;
		case T_TypeName:
			fc_loc = ((const TypeName *) fc_expr)->location;
			break;
		case T_ColumnDef:
			fc_loc = ((const ColumnDef *) fc_expr)->location;
			break;
		case T_Constraint:
			fc_loc = ((const Constraint *) fc_expr)->location;
			break;
		case T_FunctionParameter:
			/* 仅使用类型名称的位置 */
			fc_loc = exprLocation((Node *) ((const FunctionParameter *) fc_expr)->argType);
			break;
		case T_XmlSerialize:
			/* XMLSERIALIZE 关键字应该始终是第一个 */
			fc_loc = ((const XmlSerialize *) fc_expr)->location;
			break;
		case T_GroupingSet:
			fc_loc = ((const GroupingSet *) fc_expr)->location;
			break;
		case T_WithClause:
			fc_loc = ((const WithClause *) fc_expr)->location;
			break;
		case T_InferClause:
			fc_loc = ((const InferClause *) fc_expr)->location;
			break;
		case T_OnConflictClause:
			fc_loc = ((const OnConflictClause *) fc_expr)->location;
			break;
		case T_CTESearchClause:
			fc_loc = ((const CTESearchClause *) fc_expr)->location;
			break;
		case T_CTECycleClause:
			fc_loc = ((const CTECycleClause *) fc_expr)->location;
			break;
		case T_CommonTableExpr:
			fc_loc = ((const CommonTableExpr *) fc_expr)->location;
			break;
		case T_PlaceHolderVar:
			/* 仅使用参数的位置 */
			fc_loc = exprLocation((Node *) ((const PlaceHolderVar *) fc_expr)->phexpr);
			break;
		case T_InferenceElem:
			/* 仅使用嵌套表达式的位置 */
			fc_loc = exprLocation((Node *) ((const InferenceElem *) fc_expr)->expr);
			break;
		case T_PartitionElem:
			fc_loc = ((const PartitionElem *) fc_expr)->location;
			break;
		case T_PartitionSpec:
			fc_loc = ((const PartitionSpec *) fc_expr)->location;
			break;
		case T_PartitionBoundSpec:
			fc_loc = ((const PartitionBoundSpec *) fc_expr)->location;
			break;
		case T_PartitionRangeDatum:
			fc_loc = ((const PartitionRangeDatum *) fc_expr)->location;
			break;
		default:
			/* 对于任何其他节点类型，仅仅未知... */
			fc_loc = -1;
			break;
	}
	return fc_loc;
}

/* 
 * leftmostLoc - 对 exprLocation 的支持
 *
 * 取两个解析位置值的最小值，但忽略未知
 */
static int fc_leftmostLoc(int fc_loc1, int fc_loc2)
{
	if (fc_loc1 < 0)
		return fc_loc2;
	else if (fc_loc2 < 0)
		return fc_loc1;
	else
		return Min(fc_loc1, fc_loc2);
}


/* 
 * fix_opfuncids
 *	  计算给定树中每个 OpExpr 节点的 opfuncid 字段。
 *	  给定的树可以是 expression_tree_walker 处理的任何内容。
 *
 * 该参数在原地修改。（这是可以的，因为我们希望
 * 对于任何节点进行相同的更改，即使由于
 * 共享结构而被访问多次。）
 */
void fix_opfuncids(Node *fc_node)
{
	/* 此树遍历不需要特殊设置，所以我们开始吧... */
	fc_fix_opfuncids_walker(fc_node, NULL);
}

static bool fc_fix_opfuncids_walker(Node *fc_node, void *fc_context)
{
	if (fc_node == NULL)
		return false;
	if (IsA(fc_node, OpExpr))
		set_opfuncid((OpExpr *) fc_node);
	else if (IsA(fc_node, DistinctExpr))
		set_opfuncid((OpExpr *) fc_node);	/* 依赖于结构等价性 */
	else if (IsA(fc_node, NullIfExpr))
		set_opfuncid((OpExpr *) fc_node);	/* 依赖于结构等价性 */
	else if (IsA(fc_node, ScalarArrayOpExpr))
		set_sa_opfuncid((ScalarArrayOpExpr *) fc_node);
	return expression_tree_walker(fc_node, fc_fix_opfuncids_walker, fc_context);
}

/* 
 * set_opfuncid
 *		在 OpExpr 节点中设置 opfuncid（过程 OID），
 *		如果尚未设置。
 *
 * 由于结构等价性，这也可以用于
 * DistinctExpr 和 NullIfExpr 节点。
 */
void set_opfuncid(OpExpr *fc_opexpr)
{
	if (fc_opexpr->opfuncid == InvalidOid)
		fc_opexpr->opfuncid = get_opcode(fc_opexpr->opno);
}

/* 
 * set_sa_opfuncid
 *		如上所述，对于 ScalarArrayOpExpr 节点。
 */
void set_sa_opfuncid(ScalarArrayOpExpr *fc_opexpr)
{
	if (fc_opexpr->opfuncid == InvalidOid)
		fc_opexpr->opfuncid = get_opcode(fc_opexpr->opno);
}


/* 
 *	check_functions_in_node -
 *	  对给定表达式节点中包含的每个函数 OID 应用 checker()
 *
 * 如果 checker() 函数返回 true，则返回 true；对于表示多个
 * 函数调用的节点，如果 checker() 函数对于任何这些函数返回 true，则返回 true。
 * 如果节点不调用任何 SQL 可见函数，则返回 false。调用者不得传递 node == NULL。
 *
 * 此函数仅检查给定的节点；它不递归到任何子表达式中。
 * 调用者通常希望自己控制递归，以防需要进行额外检查，或因为他们
 * 对需要访问的树的某些部分有特殊规则。
 *
 * 注意：我们忽略 MinMaxExpr、SQLValueFunction、XmlExpr、CoerceToDomain，
 * 和 NextValueExpr 节点，因为它们不包含 SQL 函数 OID。
 * 然而，它们可以调用 SQL 可见函数，因此调用者应仔细考虑
 * 如何对待它们。
 */
bool check_functions_in_node(Node *fc_node, check_function_callback fc_checker,
						void *fc_context)
{
	switch (nodeTag(fc_node))
	{
		case T_Aggref:
			{
				Aggref	   *fc_expr = (Aggref *) fc_node;

				if (fc_checker(fc_expr->aggfnoid, fc_context))
					return true;
			}
			break;
		case T_WindowFunc:
			{
				WindowFunc *fc_expr = (WindowFunc *) fc_node;

				if (fc_checker(fc_expr->winfnoid, fc_context))
					return true;
			}
			break;
		case T_FuncExpr:
			{
				FuncExpr   *fc_expr = (FuncExpr *) fc_node;

				if (fc_checker(fc_expr->funcid, fc_context))
					return true;
			}
			break;
		case T_OpExpr:
		case T_DistinctExpr:	/* 相当于OpExpr的结构 */
		case T_NullIfExpr:		/* 相当于OpExpr的结构 */
			{
				OpExpr	   *fc_expr = (OpExpr *) fc_node;

				/* 如果还没有设置opfuncid，就设置它 */
				set_opfuncid(fc_expr);
				if (fc_checker(fc_expr->opfuncid, fc_context))
					return true;
			}
			break;
		case T_ScalarArrayOpExpr:
			{
				ScalarArrayOpExpr *fc_expr = (ScalarArrayOpExpr *) fc_node;

				set_sa_opfuncid(fc_expr);
				if (fc_checker(fc_expr->opfuncid, fc_context))
					return true;
			}
			break;
		case T_CoerceViaIO:
			{
				CoerceViaIO *fc_expr = (CoerceViaIO *) fc_node;
				Oid			fc_iofunc;
				Oid			fc_typioparam;
				bool		fc_typisvarlena;

				/* 检查结果类型的输入函数 */
				getTypeInputInfo(fc_expr->resulttype,
								 &fc_iofunc, &fc_typioparam);
				if (fc_checker(fc_iofunc, fc_context))
					return true;
				/* 检查输入类型的输出函数 */
				getTypeOutputInfo(exprType((Node *) fc_expr->arg),
								  &fc_iofunc, &fc_typisvarlena);
				if (fc_checker(fc_iofunc, fc_context))
					return true;
			}
			break;
		case T_RowCompareExpr:
			{
				RowCompareExpr *fc_rcexpr = (RowCompareExpr *) fc_node;
				ListCell   *fc_opid;

				foreach(fc_opid, fc_rcexpr->opnos)
				{
					Oid			fc_opfuncid = get_opcode(lfirst_oid(fc_opid));

					if (fc_checker(fc_opfuncid, fc_context))
						return true;
				}
			}
			break;
		default:
			break;
	}
	return false;
}


/*
 * 标准表达式树遍历支持
 *
 * 我们之前在许多不同的例程中有近乎重复的代码，这些代码
 * 理解如何递归遍历表达式节点树。这维护起来非常麻烦，并且我们
 * 经常由于某个特定例程忽略支持特定节点类型而导致错误。在大多数
 * 情况下，这些例程只实际关心某些节点类型，对于其他类型只关心
 * 他们必须如何递归遍历非原始节点类型。因此，我们现在提供通用
 * 的树遍历逻辑，以整合冗余的“样板”代码。提供了两个版本：
 * expression_tree_walker() 和 expression_tree_mutator()。
 */

/*
 * expression_tree_walker() 旨在支持以只读方式遍历树的例程
 * （尽管它也可以用于修改节点但从不添加/删除/替换节点的例程）。
 * 一个遍历例程应该像这样：
 *
 * bool my_walker (Node *node, my_struct *context)
 * {
 *		if (node == NULL)
 *			return false;
 *		// 检查需要特殊处理的节点，例如：
 *		if (IsA(node, Var))
 *		{
 *			... 对 Var 节点执行特殊操作
 *		}
 *		else if (IsA(node, ...))
 *		{
 *			... 对其他节点类型执行特殊操作
 *		}
 *		// 对于没有特别处理的任何节点类型，执行：
 *		return expression_tree_walker(node, my_walker, (void *) context);
 * }
 *
 * “context”参数指向一个结构，保存遍历例程需要的任何上下文
 * 信息 —— 它也可以用于返回遍历器收集的数据。此参数不被
 * expression_tree_walker 修改，但会传递给 my_walker 的递归
 * 子调用。树遍历从一个设置例程开始，该例程填写适当的上下文
 * 结构，用顶层节点调用 my_walker，然后检查结果。
 *
 * 遍历例程应返回“false”以继续树遍历，或返回“true”以中止
 * 遍历并立即返回“true”给顶层调用者。这可以用于在遍历器找到
 * 它所寻找的内容时短路遍历。如果没有任何遍历器调用返回“true”，
 * 则返回“false”给顶层调用者。
 *
 * expression_tree_walker 处理的节点类型包括在计划阶段通常
 * 找到的目标列表和限定符子句中的所有节点。特别是，它处理
 * List 节点，因为 cnf 化后的限定子句在顶层会有 List 结构，
 * 它还处理 TargetEntry 节点，以便可以在没有额外代码的情况下
 * 处理目标列表扫描。此外，RangeTblRef、FromExpr、JoinExpr 和
 * SetOperationStmt 节点也被处理，以便查询联接树和集合操作树
 * 可以在没有额外代码的情况下处理。
 *
 * expression_tree_walker 将处理 SubLink 节点，通过正常递归
 * 进入“testexpr”子树（这是属于外部计划的表达式）。它还会
 * 对子查询节点调用遍历器；然而，当 expression_tree_walker
 * 自身在一个 Query 节点上被调用时，它不执行任何操作并返回
 * “false”。净效果是，除非遍历器在 Query 节点上执行特殊
 * 操作，否则在表达式树遍历时不会访问子选择。这在许多情况下
 * 是期望的行为 —— 对于那些希望递归进入子选择的遍历器，
 * 通常在进入子选择时需要特殊处理（例如，增加深度计数器）。
 * 想要检查子选择的遍历器应该包含类似于以下代码：
 *
 *		if (IsA(node, Query))
 *		{
 *			调整上下文以适应子查询；
 *			result = query_tree_walker((Query *) node, my_walker, context,
 *									   0); // 根据需要调整标志
 *		 如果需要，恢复上下文；
 *			return result;
 *		}
 *
 * query_tree_walker 是一个便利例程（见下文），它在给定 Query
 * 节点的所有表达式子树上调用遍历器。
 *
 * expression_tree_walker 将通过正常递归进入“testexpr”和
 * “args”列表（这两个都是属于外部计划的表达式）来处理 SubPlan
 * 节点。然而，它不会触及已完成的子计划。由于没有链接到原始 Query，
 * 因此无法递归进入已经规划的表达式树的子选择。这对于当前的
 * 用途是可以的，但可能需要在未来重新审视。
 */

bool expression_tree_walker(Node *fc_node,
					   bool (*fc_walker) (),
					   void *fc_context)
{
	ListCell   *fc_temp;

	/*
	 * 遍历器已经访问了当前节点，因此我们只需要
	 * 递归访问它的任何子节点。
	 *
	 * 我们假设遍历器对 List 节点本身不感兴趣，
	 * 因此当我们期望 List 时，我们只需直接递归
	 * 到自身，而不必调用遍历器。
	 */
	if (fc_node == NULL)
		return false;

	/* 防止因过于复杂的表达式导致栈溢出 */
	check_stack_depth();

	switch (nodeTag(fc_node))
	{
		case T_Var:
		case T_Const:
		case T_Param:
		case T_CaseTestExpr:
		case T_SQLValueFunction:
		case T_CoerceToDomainValue:
		case T_SetToDefault:
		case T_CurrentOfExpr:
		case T_NextValueExpr:
		case T_RangeTblRef:
		case T_SortGroupClause:
		case T_CTESearchClause:
			
/* 原始节点类型，没有表达式子节点 */
			break;
		case T_WithCheckOption:
			return fc_walker(((WithCheckOption *) fc_node)->qual, fc_context);
		case T_Aggref:
			{
				Aggref	   *fc_expr = (Aggref *) fc_node;

				/* 直接递归到 List */
				if (expression_tree_walker((Node *) fc_expr->aggdirectargs,
										   fc_walker, fc_context))
					return true;
				if (expression_tree_walker((Node *) fc_expr->args,
										   fc_walker, fc_context))
					return true;
				if (expression_tree_walker((Node *) fc_expr->aggorder,
										   fc_walker, fc_context))
					return true;
				if (expression_tree_walker((Node *) fc_expr->aggdistinct,
										   fc_walker, fc_context))
					return true;
				if (fc_walker((Node *) fc_expr->aggfilter, fc_context))
					return true;
			}
			break;
		case T_GroupingFunc:
			{
				GroupingFunc *fc_grouping = (GroupingFunc *) fc_node;

				if (expression_tree_walker((Node *) fc_grouping->args,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_WindowFunc:
			{
				WindowFunc *fc_expr = (WindowFunc *) fc_node;

				/* 直接递归到 List */
				if (expression_tree_walker((Node *) fc_expr->args,
										   fc_walker, fc_context))
					return true;
				if (fc_walker((Node *) fc_expr->aggfilter, fc_context))
					return true;
			}
			break;
		case T_SubscriptingRef:
			{
				SubscriptingRef *fc_sbsref = (SubscriptingRef *) fc_node;

				/* 直接递归到上/下容器索引列表 */
				if (expression_tree_walker((Node *) fc_sbsref->refupperindexpr,
										   fc_walker, fc_context))
					return true;
				if (expression_tree_walker((Node *) fc_sbsref->reflowerindexpr,
										   fc_walker, fc_context))
					return true;
				/* walker 必须看到 refexpr 和 refassgnexpr，然而 */
				if (fc_walker(fc_sbsref->refexpr, fc_context))
					return true;

				if (fc_walker(fc_sbsref->refassgnexpr, fc_context))
					return true;
			}
			break;
		case T_FuncExpr:
			{
				FuncExpr   *fc_expr = (FuncExpr *) fc_node;

				if (expression_tree_walker((Node *) fc_expr->args,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_NamedArgExpr:
			return fc_walker(((NamedArgExpr *) fc_node)->arg, fc_context);
		case T_OpExpr:
		case T_DistinctExpr:	/* 相当于OpExpr的结构 */
		case T_NullIfExpr:		/* 相当于OpExpr的结构 */
			{
				OpExpr	   *fc_expr = (OpExpr *) fc_node;

				if (expression_tree_walker((Node *) fc_expr->args,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_ScalarArrayOpExpr:
			{
				ScalarArrayOpExpr *fc_expr = (ScalarArrayOpExpr *) fc_node;

				if (expression_tree_walker((Node *) fc_expr->args,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_BoolExpr:
			{
				BoolExpr   *fc_expr = (BoolExpr *) fc_node;

				if (expression_tree_walker((Node *) fc_expr->args,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_SubLink:
			{
				SubLink    *fc_sublink = (SubLink *) fc_node;

				if (fc_walker(fc_sublink->testexpr, fc_context))
					return true;

				/*
				 * 还要在子链接的 Query 节点上调用 walker，这样
				 * 它可以在需要时递归到子查询中。
				 */
				return fc_walker(fc_sublink->subselect, fc_context);
			}
			break;
		case T_SubPlan:
			{
				SubPlan    *fc_subplan = (SubPlan *) fc_node;

				/* 递归进入 testexpr，但不进入 Plan */
				if (fc_walker(fc_subplan->testexpr, fc_context))
					return true;
				/* 还要检查 args 列表 */
				if (expression_tree_walker((Node *) fc_subplan->args,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_AlternativeSubPlan:
			return fc_walker(((AlternativeSubPlan *) fc_node)->subplans, fc_context);
		case T_FieldSelect:
			return fc_walker(((FieldSelect *) fc_node)->arg, fc_context);
		case T_FieldStore:
			{
				FieldStore *fc_fstore = (FieldStore *) fc_node;

				if (fc_walker(fc_fstore->arg, fc_context))
					return true;
				if (fc_walker(fc_fstore->newvals, fc_context))
					return true;
			}
			break;
		case T_RelabelType:
			return fc_walker(((RelabelType *) fc_node)->arg, fc_context);
		case T_CoerceViaIO:
			return fc_walker(((CoerceViaIO *) fc_node)->arg, fc_context);
		case T_ArrayCoerceExpr:
			{
				ArrayCoerceExpr *fc_acoerce = (ArrayCoerceExpr *) fc_node;

				if (fc_walker(fc_acoerce->arg, fc_context))
					return true;
				if (fc_walker(fc_acoerce->elemexpr, fc_context))
					return true;
			}
			break;
		case T_ConvertRowtypeExpr:
			return fc_walker(((ConvertRowtypeExpr *) fc_node)->arg, fc_context);
		case T_CollateExpr:
			return fc_walker(((CollateExpr *) fc_node)->arg, fc_context);
		case T_CaseExpr:
			{
				CaseExpr   *fc_caseexpr = (CaseExpr *) fc_node;

				if (fc_walker(fc_caseexpr->arg, fc_context))
					return true;
				/* 我们假设 walker 不关心 CaseWhens */
				foreach(fc_temp, fc_caseexpr->args)
				{
					CaseWhen   *fc_when = lfirst_node(CaseWhen, fc_temp);

					if (fc_walker(fc_when->expr, fc_context))
						return true;
					if (fc_walker(fc_when->result, fc_context))
						return true;
				}
				if (fc_walker(fc_caseexpr->defresult, fc_context))
					return true;
			}
			break;
		case T_ArrayExpr:
			return fc_walker(((ArrayExpr *) fc_node)->elements, fc_context);
		case T_RowExpr:
			/* 假设 colnames 不重要 */
			return fc_walker(((RowExpr *) fc_node)->args, fc_context);
		case T_RowCompareExpr:
			{
				RowCompareExpr *fc_rcexpr = (RowCompareExpr *) fc_node;

				if (fc_walker(fc_rcexpr->largs, fc_context))
					return true;
				if (fc_walker(fc_rcexpr->rargs, fc_context))
					return true;
			}
			break;
		case T_CoalesceExpr:
			return fc_walker(((CoalesceExpr *) fc_node)->args, fc_context);
		case T_MinMaxExpr:
			return fc_walker(((MinMaxExpr *) fc_node)->args, fc_context);
		case T_XmlExpr:
			{
				XmlExpr    *fc_xexpr = (XmlExpr *) fc_node;

				if (fc_walker(fc_xexpr->named_args, fc_context))
					return true;
				/* 我们假设 walker 不关心 arg_names */
				if (fc_walker(fc_xexpr->args, fc_context))
					return true;
			}
			break;
		case T_NullTest:
			return fc_walker(((NullTest *) fc_node)->arg, fc_context);
		case T_BooleanTest:
			return fc_walker(((BooleanTest *) fc_node)->arg, fc_context);
		case T_CoerceToDomain:
			return fc_walker(((CoerceToDomain *) fc_node)->arg, fc_context);
		case T_TargetEntry:
			return fc_walker(((TargetEntry *) fc_node)->expr, fc_context);
		case T_Query:
			/* 根据以上讨论，对子查询不做任何处理 */
			break;
		case T_WindowClause:
			{
				WindowClause *fc_wc = (WindowClause *) fc_node;

				if (fc_walker(fc_wc->partitionClause, fc_context))
					return true;
				if (fc_walker(fc_wc->orderClause, fc_context))
					return true;
				if (fc_walker(fc_wc->startOffset, fc_context))
					return true;
				if (fc_walker(fc_wc->endOffset, fc_context))
					return true;
				if (fc_walker(fc_wc->runCondition, fc_context))
					return true;
			}
			break;
		case T_CTECycleClause:
			{
				CTECycleClause *fc_cc = (CTECycleClause *) fc_node;

				if (fc_walker(fc_cc->cycle_mark_value, fc_context))
					return true;
				if (fc_walker(fc_cc->cycle_mark_default, fc_context))
					return true;
			}
			break;
		case T_CommonTableExpr:
			{
				CommonTableExpr *fc_cte = (CommonTableExpr *) fc_node;

				/*
				 * 在 CTE 的 Query 节点上调用 walker，这样它可以
				 * 在需要时递归到子查询中。
				 */
				if (fc_walker(fc_cte->ctequery, fc_context))
					return true;

				if (fc_walker(fc_cte->search_clause, fc_context))
					return true;
				if (fc_walker(fc_cte->cycle_clause, fc_context))
					return true;
			}
			break;
		case T_PartitionBoundSpec:
			{
				PartitionBoundSpec *fc_pbs = (PartitionBoundSpec *) fc_node;

				if (fc_walker(fc_pbs->listdatums, fc_context))
					return true;
				if (fc_walker(fc_pbs->lowerdatums, fc_context))
					return true;
				if (fc_walker(fc_pbs->upperdatums, fc_context))
					return true;
			}
			break;
		case T_PartitionRangeDatum:
			{
				PartitionRangeDatum *fc_prd = (PartitionRangeDatum *) fc_node;

				if (fc_walker(fc_prd->value, fc_context))
					return true;
			}
			break;
		case T_List:
			foreach(fc_temp, (List *) fc_node)
			{
				if (fc_walker((Node *) lfirst(fc_temp), fc_context))
					return true;
			}
			break;
		case T_FromExpr:
			{
				FromExpr   *fc_from = (FromExpr *) fc_node;

				if (fc_walker(fc_from->fromlist, fc_context))
					return true;
				if (fc_walker(fc_from->quals, fc_context))
					return true;
			}
			break;
		case T_OnConflictExpr:
			{
				OnConflictExpr *fc_onconflict = (OnConflictExpr *) fc_node;

				if (fc_walker((Node *) fc_onconflict->arbiterElems, fc_context))
					return true;
				if (fc_walker(fc_onconflict->arbiterWhere, fc_context))
					return true;
				if (fc_walker(fc_onconflict->onConflictSet, fc_context))
					return true;
				if (fc_walker(fc_onconflict->onConflictWhere, fc_context))
					return true;
				if (fc_walker(fc_onconflict->exclRelTlist, fc_context))
					return true;
			}
			break;
		case T_MergeAction:
			{
				MergeAction *fc_action = (MergeAction *) fc_node;

				if (fc_walker(fc_action->qual, fc_context))
					return true;
				if (fc_walker(fc_action->targetList, fc_context))
					return true;
			}
			break;
		case T_PartitionPruneStepOp:
			{
				PartitionPruneStepOp *fc_opstep = (PartitionPruneStepOp *) fc_node;

				if (fc_walker((Node *) fc_opstep->exprs, fc_context))
					return true;
			}
			break;
		case T_PartitionPruneStepCombine:
			/* 没有表达式子节点 */
			break;
		case T_JoinExpr:
			{
				JoinExpr   *fc_join = (JoinExpr *) fc_node;

				if (fc_walker(fc_join->larg, fc_context))
					return true;
				if (fc_walker(fc_join->rarg, fc_context))
					return true;
				if (fc_walker(fc_join->quals, fc_context))
					return true;

				/*
				 * 别名子句，使用的列表被认为不重要。
				 */
			}
			break;
		case T_SetOperationStmt:
			{
				SetOperationStmt *fc_setop = (SetOperationStmt *) fc_node;

				if (fc_walker(fc_setop->larg, fc_context))
					return true;
				if (fc_walker(fc_setop->rarg, fc_context))
					return true;

				/* groupClauses 被认为不重要 */
			}
			break;
		case T_IndexClause:
			{
				IndexClause *fc_iclause = (IndexClause *) fc_node;

				if (fc_walker(fc_iclause->rinfo, fc_context))
					return true;
				if (expression_tree_walker((Node *) fc_iclause->indexquals,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_PlaceHolderVar:
			return fc_walker(((PlaceHolderVar *) fc_node)->phexpr, fc_context);
		case T_InferenceElem:
			return fc_walker(((InferenceElem *) fc_node)->expr, fc_context);
		case T_AppendRelInfo:
			{
				AppendRelInfo *fc_appinfo = (AppendRelInfo *) fc_node;

				if (expression_tree_walker((Node *) fc_appinfo->translated_vars,
										   fc_walker, fc_context))
					return true;
			}
			break;
		case T_PlaceHolderInfo:
			return fc_walker(((PlaceHolderInfo *) fc_node)->ph_var, fc_context);
		case T_RangeTblFunction:
			return fc_walker(((RangeTblFunction *) fc_node)->funcexpr, fc_context);
		case T_TableSampleClause:
			{
				TableSampleClause *fc_tsc = (TableSampleClause *) fc_node;

				if (expression_tree_walker((Node *) fc_tsc->args,
										   fc_walker, fc_context))
					return true;
				if (fc_walker((Node *) fc_tsc->repeatable, fc_context))
					return true;
			}
			break;
		case T_TableFunc:
			{
				TableFunc  *fc_tf = (TableFunc *) fc_node;

				if (fc_walker(fc_tf->ns_uris, fc_context))
					return true;
				if (fc_walker(fc_tf->docexpr, fc_context))
					return true;
				if (fc_walker(fc_tf->rowexpr, fc_context))
					return true;
				if (fc_walker(fc_tf->colexprs, fc_context))
					return true;
				if (fc_walker(fc_tf->coldefexprs, fc_context))
					return true;
			}
			break;
		default:
			elog(ERROR, "unrecognized node type: %d",
				 (int) nodeTag(fc_node));
			break;
	}
	return false;
}

/*
 * query_tree_walker --- 启动一个 Query 表达式的遍历
 *
 * 此例程的存在是为了减少需要知道
 * 查询的所有表达式子树位置的地方。请注意，它可以用于
 * 在 Query 顶层开始遍历，无论 walker 是否打算
 * 进入子查询。它在 walker 进入子查询时也很有用。
 *
 * 一些调用者希望抑制对子查询中特定项目的访问，
 * 通常是因为他们需要特殊处理这些项目，或者实际上
 * 不希望递归进入子查询。通过 flags 参数支持这种功能，
 * 该参数是要添加或抑制访问的项目的标志值的按位或。
 * （根据需要，可以添加更多标志位。）
 */
bool query_tree_walker(Query *fc_query,
				  bool (*fc_walker) (),
				  void *fc_context,
				  int fc_flags)
{
	Assert(fc_query != NULL && IsA(fc_query, Query));

	/*
	 * 我们在这里不遍历任何 utilityStmt。然而，我们不能轻易地断言
	 * 它不存在，因为至少有两条代码路径可以让
	 * CREATE RULE 的 action 语句到达这里，并且在规则动作中允许
	 * NOTIFY。
	 */

	if (fc_walker((Node *) fc_query->targetList, fc_context))
		return true;
	if (fc_walker((Node *) fc_query->withCheckOptions, fc_context))
		return true;
	if (fc_walker((Node *) fc_query->onConflict, fc_context))
		return true;
	if (fc_walker((Node *) fc_query->mergeActionList, fc_context))
		return true;
	if (fc_walker((Node *) fc_query->returningList, fc_context))
		return true;
	if (fc_walker((Node *) fc_query->jointree, fc_context))
		return true;
	if (fc_walker(fc_query->setOperations, fc_context))
		return true;
	if (fc_walker(fc_query->havingQual, fc_context))
		return true;
	if (fc_walker(fc_query->limitOffset, fc_context))
		return true;
	if (fc_walker(fc_query->limitCount, fc_context))
		return true;

	/*
	 * 大多数调用者对 SortGroupClause 节点不感兴趣，因为这些
	 * 节点不包含实际的表达式。然而，它们确实包含可能
	 * 被依赖遍历器等需要的 OID。
	 */
	if ((fc_flags & QTW_EXAMINE_SORTGROUP))
	{
		if (fc_walker((Node *) fc_query->groupClause, fc_context))
			return true;
		if (fc_walker((Node *) fc_query->windowClause, fc_context))
			return true;
		if (fc_walker((Node *) fc_query->sortClause, fc_context))
			return true;
		if (fc_walker((Node *) fc_query->distinctClause, fc_context))
			return true;
	}
	else
	{
		/*
		 * 但是即使我们不关心 SortGroupClause 节点，我们仍然需要遍历
		 * WindowClause 节点下的表达式。
		 */
		ListCell   *fc_lc;

		foreach(fc_lc, fc_query->windowClause)
		{
			WindowClause *fc_wc = lfirst_node(WindowClause, fc_lc);

			if (fc_walker(fc_wc->startOffset, fc_context))
				return true;
			if (fc_walker(fc_wc->endOffset, fc_context))
				return true;
			if (fc_walker(fc_wc->runCondition, fc_context))
				return true;
		}
	}

	/*
	 * groupingSets 和 rowMarks 不进行遍历：
	 *
	 * groupingSets 仅包含 ressortgrouprefs（整数），
	 * 没有相应的 groupClause 或 tlist 意义不明。
	 * 因此，任何需要关心它们的 walker 都需要在其 Query 处理
	 * 中自行处理。
	 *
	 * rowMarks 不进行遍历，因为它仅包含 rangetable 索引（和
	 * 标志等），因此应该在 Query 级别类似地处理。
	 */

	if (!(fc_flags & QTW_IGNORE_CTE_SUBQUERIES))
	{
		if (fc_walker((Node *) fc_query->cteList, fc_context))
			return true;
	}
	if (!(fc_flags & QTW_IGNORE_RANGE_TABLE))
	{
		if (range_table_walker(fc_query->rtable, fc_walker, fc_context, fc_flags))
			return true;
	}
	return false;
}

/*
 * range_table_walker 只是 query_tree_walker 中扫描
 * 查询的 rangetable 的部分。这部分拆分开是因为它单独使用时
 * 也可能很有用。
 */
bool range_table_walker(List *fc_rtable,
				   bool (*fc_walker) (),
				   void *fc_context,
				   int fc_flags)
{
	ListCell   *fc_rt;

	foreach(fc_rt, fc_rtable)
	{
		RangeTblEntry *fc_rte = lfirst_node(RangeTblEntry, fc_rt);

		if (range_table_entry_walker(fc_rte, fc_walker, fc_context, fc_flags))
			return true;
	}
	return false;
}

/*
 * 一些调用者甚至希望扫描单个 RTE 中的表达式。
 */
bool range_table_entry_walker(RangeTblEntry *fc_rte,
						 bool (*fc_walker) (),
						 void *fc_context,
						 int fc_flags)
{
	/*
	 * walker 可能需要在访问其内容之前或之后检查 RTE 节点
	 * （或者，可能两者都需要）。请注意，如果您不指定任何标志，
	 * walker 将根本不会被调用到 RTE 上。
	 */
	if (fc_flags & QTW_EXAMINE_RTES_BEFORE)
		if (fc_walker(fc_rte, fc_context))
			return true;

	switch (fc_rte->rtekind)
	{
		case RTE_RELATION:
			if (fc_walker(fc_rte->tablesample, fc_context))
				return true;
			break;
		case RTE_SUBQUERY:
			if (!(fc_flags & QTW_IGNORE_RT_SUBQUERIES))
				if (fc_walker(fc_rte->subquery, fc_context))
					return true;
			break;
		case RTE_JOIN:
			if (!(fc_flags & QTW_IGNORE_JOINALIASES))
				if (fc_walker(fc_rte->joinaliasvars, fc_context))
					return true;
			break;
		case RTE_FUNCTION:
			if (fc_walker(fc_rte->functions, fc_context))
				return true;
			break;
		case RTE_TABLEFUNC:
			if (fc_walker(fc_rte->tablefunc, fc_context))
				return true;
			break;
		case RTE_VALUES:
			if (fc_walker(fc_rte->values_lists, fc_context))
				return true;
			break;
		case RTE_CTE:
		case RTE_NAMEDTUPLESTORE:
		case RTE_RESULT:
			/* 无需操作 */
			break;
	}

	if (fc_walker(fc_rte->securityQuals, fc_context))
		return true;

	if (fc_flags & QTW_EXAMINE_RTES_AFTER)
		if (fc_walker(fc_rte, fc_context))
			return true;

	return false;
}




Node * expression_tree_mutator(Node *fc_node,
						Node *(*fc_mutator) (),
						void *fc_context)
{
	/*
	 * 变异器已经决定不修改当前节点，但我们必须对任何子节点调用变异器。
	 */

#define FLATCOPY(newnode, node, nodetype)  \
	( (newnode) = (nodetype *) palloc(sizeof(nodetype)), \
	  memcpy((newnode), (node), sizeof(nodetype)) )

#define MUTATE(newfield, oldfield, fieldtype)  \
		( (newfield) = (fieldtype) fc_mutator((Node *) (oldfield), fc_context) )

	if (fc_node == NULL)
		return NULL;

	/* 防止因过于复杂的表达式导致栈溢出 */
	check_stack_depth();

	switch (nodeTag(fc_node))
	{
			/*
			 * 没有表达式子节点的原始节点类型。Var 和
			 * Const 足够频繁，值得特殊处理，其余的我们就使用 copyObject。
			 */
		case T_Var:
			{
				Var		   *fc_var = (Var *) fc_node;
				Var		   *fc_newnode;

				FLATCOPY(fc_newnode, fc_var, Var);
				return (Node *) fc_newnode;
			}
			break;
		case T_Const:
			{
				Const	   *fc_oldnode = (Const *) fc_node;
				Const	   *fc_newnode;

				FLATCOPY(fc_newnode, fc_oldnode, Const);
				/* XXX 我们不在乎 datumCopy；我们应该在乎吗？ */
				return (Node *) fc_newnode;
			}
			break;
		case T_Param:
		case T_CaseTestExpr:
		case T_SQLValueFunction:
		case T_CoerceToDomainValue:
		case T_SetToDefault:
		case T_CurrentOfExpr:
		case T_NextValueExpr:
		case T_RangeTblRef:
		case T_SortGroupClause:
		case T_CTESearchClause:
			return (Node *) copyObject(fc_node);
		case T_WithCheckOption:
			{
				WithCheckOption *fc_wco = (WithCheckOption *) fc_node;
				WithCheckOption *fc_newnode;

				FLATCOPY(fc_newnode, fc_wco, WithCheckOption);
				MUTATE(fc_newnode->qual, fc_wco->qual, Node *);
				return (Node *) fc_newnode;
			}
		case T_Aggref:
			{
				Aggref	   *fc_aggref = (Aggref *) fc_node;
				Aggref	   *fc_newnode;

				FLATCOPY(fc_newnode, fc_aggref, Aggref);
				/* 假设变异不会改变参数的类型 */
				fc_newnode->aggargtypes = list_copy(fc_aggref->aggargtypes);
				MUTATE(fc_newnode->aggdirectargs, fc_aggref->aggdirectargs, List *);
				MUTATE(fc_newnode->args, fc_aggref->args, List *);
				MUTATE(fc_newnode->aggorder, fc_aggref->aggorder, List *);
				MUTATE(fc_newnode->aggdistinct, fc_aggref->aggdistinct, List *);
				MUTATE(fc_newnode->aggfilter, fc_aggref->aggfilter, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_GroupingFunc:
			{
				GroupingFunc *fc_grouping = (GroupingFunc *) fc_node;
				GroupingFunc *fc_newnode;

				FLATCOPY(fc_newnode, fc_grouping, GroupingFunc);
				MUTATE(fc_newnode->args, fc_grouping->args, List *);

				/*
				 * 我们在这里假设对参数的变异不会改变语义，即参数
				 * 并未以使其在 GROUP BY 子句中与之前匹配的
				 * 表达式在语义上不同的方式进行变异。
				 *
				 * 如果变异器想要这样做，它必须自行适当处理 refs
				 * 和 cols 列表。
				 */
				fc_newnode->refs = list_copy(fc_grouping->refs);
				fc_newnode->cols = list_copy(fc_grouping->cols);

				return (Node *) fc_newnode;
			}
			break;
		case T_WindowFunc:
			{
				WindowFunc *fc_wfunc = (WindowFunc *) fc_node;
				WindowFunc *fc_newnode;

				FLATCOPY(fc_newnode, fc_wfunc, WindowFunc);
				MUTATE(fc_newnode->args, fc_wfunc->args, List *);
				MUTATE(fc_newnode->aggfilter, fc_wfunc->aggfilter, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_SubscriptingRef:
			{
				SubscriptingRef *fc_sbsref = (SubscriptingRef *) fc_node;
				SubscriptingRef *fc_newnode;

				FLATCOPY(fc_newnode, fc_sbsref, SubscriptingRef);
				MUTATE(fc_newnode->refupperindexpr, fc_sbsref->refupperindexpr,
					   List *);
				MUTATE(fc_newnode->reflowerindexpr, fc_sbsref->reflowerindexpr,
					   List *);
				MUTATE(fc_newnode->refexpr, fc_sbsref->refexpr,
					   Expr *);
				MUTATE(fc_newnode->refassgnexpr, fc_sbsref->refassgnexpr,
					   Expr *);

				return (Node *) fc_newnode;
			}
			break;
		case T_FuncExpr:
			{
				FuncExpr   *fc_expr = (FuncExpr *) fc_node;
				FuncExpr   *fc_newnode;

				FLATCOPY(fc_newnode, fc_expr, FuncExpr);
				MUTATE(fc_newnode->args, fc_expr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_NamedArgExpr:
			{
				NamedArgExpr *fc_nexpr = (NamedArgExpr *) fc_node;
				NamedArgExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_nexpr, NamedArgExpr);
				MUTATE(fc_newnode->arg, fc_nexpr->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_OpExpr:
			{
				OpExpr	   *fc_expr = (OpExpr *) fc_node;
				OpExpr	   *fc_newnode;

				FLATCOPY(fc_newnode, fc_expr, OpExpr);
				MUTATE(fc_newnode->args, fc_expr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_DistinctExpr:
			{
				DistinctExpr *fc_expr = (DistinctExpr *) fc_node;
				DistinctExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_expr, DistinctExpr);
				MUTATE(fc_newnode->args, fc_expr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_NullIfExpr:
			{
				NullIfExpr *fc_expr = (NullIfExpr *) fc_node;
				NullIfExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_expr, NullIfExpr);
				MUTATE(fc_newnode->args, fc_expr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_ScalarArrayOpExpr:
			{
				ScalarArrayOpExpr *fc_expr = (ScalarArrayOpExpr *) fc_node;
				ScalarArrayOpExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_expr, ScalarArrayOpExpr);
				MUTATE(fc_newnode->args, fc_expr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_BoolExpr:
			{
				BoolExpr   *fc_expr = (BoolExpr *) fc_node;
				BoolExpr   *fc_newnode;

				FLATCOPY(fc_newnode, fc_expr, BoolExpr);
				MUTATE(fc_newnode->args, fc_expr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_SubLink:
			{
				SubLink    *fc_sublink = (SubLink *) fc_node;
				SubLink    *fc_newnode;

				FLATCOPY(fc_newnode, fc_sublink, SubLink);
				MUTATE(fc_newnode->testexpr, fc_sublink->testexpr, Node *);

				/*
				 * 还需对子链接的查询节点调用变异器，以便它能在需要时递归到
				 * 子查询中。
				 */
				MUTATE(fc_newnode->subselect, fc_sublink->subselect, Node *);
				return (Node *) fc_newnode;
			}
			break;
		case T_SubPlan:
			{
				SubPlan    *fc_subplan = (SubPlan *) fc_node;
				SubPlan    *fc_newnode;

				FLATCOPY(fc_newnode, fc_subplan, SubPlan);
				/* 转换测试表达式 */
				MUTATE(fc_newnode->testexpr, fc_subplan->testexpr, Node *);
				/* 转换参数列表（传递给子计划的参数） */
				MUTATE(fc_newnode->args, fc_subplan->args, List *);
				/* 但不包括子计划本身，后者按原样引用 */
				return (Node *) fc_newnode;
			}
			break;
		case T_AlternativeSubPlan:
			{
				AlternativeSubPlan *fc_asplan = (AlternativeSubPlan *) fc_node;
				AlternativeSubPlan *fc_newnode;

				FLATCOPY(fc_newnode, fc_asplan, AlternativeSubPlan);
				MUTATE(fc_newnode->subplans, fc_asplan->subplans, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_FieldSelect:
			{
				FieldSelect *fc_fselect = (FieldSelect *) fc_node;
				FieldSelect *fc_newnode;

				FLATCOPY(fc_newnode, fc_fselect, FieldSelect);
				MUTATE(fc_newnode->arg, fc_fselect->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_FieldStore:
			{
				FieldStore *fc_fstore = (FieldStore *) fc_node;
				FieldStore *fc_newnode;

				FLATCOPY(fc_newnode, fc_fstore, FieldStore);
				MUTATE(fc_newnode->arg, fc_fstore->arg, Expr *);
				MUTATE(fc_newnode->newvals, fc_fstore->newvals, List *);
				fc_newnode->fieldnums = list_copy(fc_fstore->fieldnums);
				return (Node *) fc_newnode;
			}
			break;
		case T_RelabelType:
			{
				RelabelType *fc_relabel = (RelabelType *) fc_node;
				RelabelType *fc_newnode;

				FLATCOPY(fc_newnode, fc_relabel, RelabelType);
				MUTATE(fc_newnode->arg, fc_relabel->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CoerceViaIO:
			{
				CoerceViaIO *fc_iocoerce = (CoerceViaIO *) fc_node;
				CoerceViaIO *fc_newnode;

				FLATCOPY(fc_newnode, fc_iocoerce, CoerceViaIO);
				MUTATE(fc_newnode->arg, fc_iocoerce->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_ArrayCoerceExpr:
			{
				ArrayCoerceExpr *fc_acoerce = (ArrayCoerceExpr *) fc_node;
				ArrayCoerceExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_acoerce, ArrayCoerceExpr);
				MUTATE(fc_newnode->arg, fc_acoerce->arg, Expr *);
				MUTATE(fc_newnode->elemexpr, fc_acoerce->elemexpr, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_ConvertRowtypeExpr:
			{
				ConvertRowtypeExpr *fc_convexpr = (ConvertRowtypeExpr *) fc_node;
				ConvertRowtypeExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_convexpr, ConvertRowtypeExpr);
				MUTATE(fc_newnode->arg, fc_convexpr->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CollateExpr:
			{
				CollateExpr *fc_collate = (CollateExpr *) fc_node;
				CollateExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_collate, CollateExpr);
				MUTATE(fc_newnode->arg, fc_collate->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CaseExpr:
			{
				CaseExpr   *fc_caseexpr = (CaseExpr *) fc_node;
				CaseExpr   *fc_newnode;

				FLATCOPY(fc_newnode, fc_caseexpr, CaseExpr);
				MUTATE(fc_newnode->arg, fc_caseexpr->arg, Expr *);
				MUTATE(fc_newnode->args, fc_caseexpr->args, List *);
				MUTATE(fc_newnode->defresult, fc_caseexpr->defresult, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CaseWhen:
			{
				CaseWhen   *fc_casewhen = (CaseWhen *) fc_node;
				CaseWhen   *fc_newnode;

				FLATCOPY(fc_newnode, fc_casewhen, CaseWhen);
				MUTATE(fc_newnode->expr, fc_casewhen->expr, Expr *);
				MUTATE(fc_newnode->result, fc_casewhen->result, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_ArrayExpr:
			{
				ArrayExpr  *fc_arrayexpr = (ArrayExpr *) fc_node;
				ArrayExpr  *fc_newnode;

				FLATCOPY(fc_newnode, fc_arrayexpr, ArrayExpr);
				MUTATE(fc_newnode->elements, fc_arrayexpr->elements, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_RowExpr:
			{
				RowExpr    *fc_rowexpr = (RowExpr *) fc_node;
				RowExpr    *fc_newnode;

				FLATCOPY(fc_newnode, fc_rowexpr, RowExpr);
				MUTATE(fc_newnode->args, fc_rowexpr->args, List *);
				/* 假设列名不需要重复 */
				return (Node *) fc_newnode;
			}
			break;
		case T_RowCompareExpr:
			{
				RowCompareExpr *fc_rcexpr = (RowCompareExpr *) fc_node;
				RowCompareExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_rcexpr, RowCompareExpr);
				MUTATE(fc_newnode->largs, fc_rcexpr->largs, List *);
				MUTATE(fc_newnode->rargs, fc_rcexpr->rargs, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CoalesceExpr:
			{
				CoalesceExpr *fc_coalesceexpr = (CoalesceExpr *) fc_node;
				CoalesceExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_coalesceexpr, CoalesceExpr);
				MUTATE(fc_newnode->args, fc_coalesceexpr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_MinMaxExpr:
			{
				MinMaxExpr *fc_minmaxexpr = (MinMaxExpr *) fc_node;
				MinMaxExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_minmaxexpr, MinMaxExpr);
				MUTATE(fc_newnode->args, fc_minmaxexpr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_XmlExpr:
			{
				XmlExpr    *fc_xexpr = (XmlExpr *) fc_node;
				XmlExpr    *fc_newnode;

				FLATCOPY(fc_newnode, fc_xexpr, XmlExpr);
				MUTATE(fc_newnode->named_args, fc_xexpr->named_args, List *);
				/* 假设变异器不关心 arg_names */
				MUTATE(fc_newnode->args, fc_xexpr->args, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_NullTest:
			{
				NullTest   *fc_ntest = (NullTest *) fc_node;
				NullTest   *fc_newnode;

				FLATCOPY(fc_newnode, fc_ntest, NullTest);
				MUTATE(fc_newnode->arg, fc_ntest->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_BooleanTest:
			{
				BooleanTest *fc_btest = (BooleanTest *) fc_node;
				BooleanTest *fc_newnode;

				FLATCOPY(fc_newnode, fc_btest, BooleanTest);
				MUTATE(fc_newnode->arg, fc_btest->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CoerceToDomain:
			{
				CoerceToDomain *fc_ctest = (CoerceToDomain *) fc_node;
				CoerceToDomain *fc_newnode;

				FLATCOPY(fc_newnode, fc_ctest, CoerceToDomain);
				MUTATE(fc_newnode->arg, fc_ctest->arg, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_TargetEntry:
			{
				TargetEntry *fc_targetentry = (TargetEntry *) fc_node;
				TargetEntry *fc_newnode;

				FLATCOPY(fc_newnode, fc_targetentry, TargetEntry);
				MUTATE(fc_newnode->expr, fc_targetentry->expr, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_Query:
			/* 根据以上讨论，对子查询不做任何处理 */
			return fc_node;
		case T_WindowClause:
			{
				WindowClause *fc_wc = (WindowClause *) fc_node;
				WindowClause *fc_newnode;

				FLATCOPY(fc_newnode, fc_wc, WindowClause);
				MUTATE(fc_newnode->partitionClause, fc_wc->partitionClause, List *);
				MUTATE(fc_newnode->orderClause, fc_wc->orderClause, List *);
				MUTATE(fc_newnode->startOffset, fc_wc->startOffset, Node *);
				MUTATE(fc_newnode->endOffset, fc_wc->endOffset, Node *);
				MUTATE(fc_newnode->runCondition, fc_wc->runCondition, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CTECycleClause:
			{
				CTECycleClause *fc_cc = (CTECycleClause *) fc_node;
				CTECycleClause *fc_newnode;

				FLATCOPY(fc_newnode, fc_cc, CTECycleClause);
				MUTATE(fc_newnode->cycle_mark_value, fc_cc->cycle_mark_value, Node *);
				MUTATE(fc_newnode->cycle_mark_default, fc_cc->cycle_mark_default, Node *);
				return (Node *) fc_newnode;
			}
			break;
		case T_CommonTableExpr:
			{
				CommonTableExpr *fc_cte = (CommonTableExpr *) fc_node;
				CommonTableExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_cte, CommonTableExpr);

				/*
				 * 还需对 CTE 的查询节点调用变异器，以便它能在需要时递归到
				 * 子查询中。
				 */
				MUTATE(fc_newnode->ctequery, fc_cte->ctequery, Node *);

				MUTATE(fc_newnode->search_clause, fc_cte->search_clause, CTESearchClause *);
				MUTATE(fc_newnode->cycle_clause, fc_cte->cycle_clause, CTECycleClause *);

				return (Node *) fc_newnode;
			}
			break;
		case T_PartitionBoundSpec:
			{
				PartitionBoundSpec *fc_pbs = (PartitionBoundSpec *) fc_node;
				PartitionBoundSpec *fc_newnode;

				FLATCOPY(fc_newnode, fc_pbs, PartitionBoundSpec);
				MUTATE(fc_newnode->listdatums, fc_pbs->listdatums, List *);
				MUTATE(fc_newnode->lowerdatums, fc_pbs->lowerdatums, List *);
				MUTATE(fc_newnode->upperdatums, fc_pbs->upperdatums, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_PartitionRangeDatum:
			{
				PartitionRangeDatum *fc_prd = (PartitionRangeDatum *) fc_node;
				PartitionRangeDatum *fc_newnode;

				FLATCOPY(fc_newnode, fc_prd, PartitionRangeDatum);
				MUTATE(fc_newnode->value, fc_prd->value, Node *);
				return (Node *) fc_newnode;
			}
			break;
		case T_List:
			{
				/*
				 * 我们假设变异器对列表节点本身不感兴趣，因此只需对每个列表元素
				 * 调用它。注意：这在包含整数元素的列表上会严重失效！
				 */
				List	   *fc_resultlist;
				ListCell   *fc_temp;

				fc_resultlist = NIL;
				foreach(fc_temp, (List *) fc_node)
				{
					fc_resultlist = lappend(fc_resultlist,
										 fc_mutator((Node *) lfirst(fc_temp),
												 fc_context));
				}
				return (Node *) fc_resultlist;
			}
			break;
		case T_FromExpr:
			{
				FromExpr   *fc_from = (FromExpr *) fc_node;
				FromExpr   *fc_newnode;

				FLATCOPY(fc_newnode, fc_from, FromExpr);
				MUTATE(fc_newnode->fromlist, fc_from->fromlist, List *);
				MUTATE(fc_newnode->quals, fc_from->quals, Node *);
				return (Node *) fc_newnode;
			}
			break;
		case T_OnConflictExpr:
			{
				OnConflictExpr *fc_oc = (OnConflictExpr *) fc_node;
				OnConflictExpr *fc_newnode;

				FLATCOPY(fc_newnode, fc_oc, OnConflictExpr);
				MUTATE(fc_newnode->arbiterElems, fc_oc->arbiterElems, List *);
				MUTATE(fc_newnode->arbiterWhere, fc_oc->arbiterWhere, Node *);
				MUTATE(fc_newnode->onConflictSet, fc_oc->onConflictSet, List *);
				MUTATE(fc_newnode->onConflictWhere, fc_oc->onConflictWhere, Node *);
				MUTATE(fc_newnode->exclRelTlist, fc_oc->exclRelTlist, List *);

				return (Node *) fc_newnode;
			}
			break;
		case T_MergeAction:
			{
				MergeAction *fc_action = (MergeAction *) fc_node;
				MergeAction *fc_newnode;

				FLATCOPY(fc_newnode, fc_action, MergeAction);
				MUTATE(fc_newnode->qual, fc_action->qual, Node *);
				MUTATE(fc_newnode->targetList, fc_action->targetList, List *);

				return (Node *) fc_newnode;
			}
			break;
		case T_PartitionPruneStepOp:
			{
				PartitionPruneStepOp *fc_opstep = (PartitionPruneStepOp *) fc_node;
				PartitionPruneStepOp *fc_newnode;

				FLATCOPY(fc_newnode, fc_opstep, PartitionPruneStepOp);
				MUTATE(fc_newnode->exprs, fc_opstep->exprs, List *);

				return (Node *) fc_newnode;
			}
			break;
		case T_PartitionPruneStepCombine:
			/* 无表达式子节点 */
			return (Node *) copyObject(fc_node);
		case T_JoinExpr:
			{
				JoinExpr   *fc_join = (JoinExpr *) fc_node;
				JoinExpr   *fc_newnode;

				FLATCOPY(fc_newnode, fc_join, JoinExpr);
				MUTATE(fc_newnode->larg, fc_join->larg, Node *);
				MUTATE(fc_newnode->rarg, fc_join->rarg, Node *);
				MUTATE(fc_newnode->quals, fc_join->quals, Node *);
				/* 默认情况下我们不变异 alias 或 using */
				return (Node *) fc_newnode;
			}
			break;
		case T_SetOperationStmt:
			{
				SetOperationStmt *fc_setop = (SetOperationStmt *) fc_node;
				SetOperationStmt *fc_newnode;

				FLATCOPY(fc_newnode, fc_setop, SetOperationStmt);
				MUTATE(fc_newnode->larg, fc_setop->larg, Node *);
				MUTATE(fc_newnode->rarg, fc_setop->rarg, Node *);
				/* 默认情况下我们不变异 groupClauses */
				return (Node *) fc_newnode;
			}
			break;
		case T_IndexClause:
			{
				IndexClause *fc_iclause = (IndexClause *) fc_node;
				IndexClause *fc_newnode;

				FLATCOPY(fc_newnode, fc_iclause, IndexClause);
				MUTATE(fc_newnode->rinfo, fc_iclause->rinfo, RestrictInfo *);
				MUTATE(fc_newnode->indexquals, fc_iclause->indexquals, List *);
				return (Node *) fc_newnode;
			}
			break;
		case T_PlaceHolderVar:
			{
				PlaceHolderVar *fc_phv = (PlaceHolderVar *) fc_node;
				PlaceHolderVar *fc_newnode;

				FLATCOPY(fc_newnode, fc_phv, PlaceHolderVar);
				MUTATE(fc_newnode->phexpr, fc_phv->phexpr, Expr *);
				/* 假设我们不需要复制 relids 位图集 */
				return (Node *) fc_newnode;
			}
			break;
		case T_InferenceElem:
			{
				InferenceElem *fc_inferenceelemdexpr = (InferenceElem *) fc_node;
				InferenceElem *fc_newnode;

				FLATCOPY(fc_newnode, fc_inferenceelemdexpr, InferenceElem);
				MUTATE(fc_newnode->expr, fc_newnode->expr, Node *);
				return (Node *) fc_newnode;
			}
			break;
		case T_AppendRelInfo:
			{
				AppendRelInfo *fc_appinfo = (AppendRelInfo *) fc_node;
				AppendRelInfo *fc_newnode;

				FLATCOPY(fc_newnode, fc_appinfo, AppendRelInfo);
				MUTATE(fc_newnode->translated_vars, fc_appinfo->translated_vars, List *);
				/* 假设对 parent_colnos[] 不需要做任何事 */
				return (Node *) fc_newnode;
			}
			break;
		case T_PlaceHolderInfo:
			{
				PlaceHolderInfo *fc_phinfo = (PlaceHolderInfo *) fc_node;
				PlaceHolderInfo *fc_newnode;

				FLATCOPY(fc_newnode, fc_phinfo, PlaceHolderInfo);
				MUTATE(fc_newnode->ph_var, fc_phinfo->ph_var, PlaceHolderVar *);
				/* 假设我们不需要复制 relids 位图集 */
				return (Node *) fc_newnode;
			}
			break;
		case T_RangeTblFunction:
			{
				RangeTblFunction *fc_rtfunc = (RangeTblFunction *) fc_node;
				RangeTblFunction *fc_newnode;

				FLATCOPY(fc_newnode, fc_rtfunc, RangeTblFunction);
				MUTATE(fc_newnode->funcexpr, fc_rtfunc->funcexpr, Node *);
				/* 假设我们不需要复制 coldef 信息列表 */
				return (Node *) fc_newnode;
			}
			break;
		case T_TableSampleClause:
			{
				TableSampleClause *fc_tsc = (TableSampleClause *) fc_node;
				TableSampleClause *fc_newnode;

				FLATCOPY(fc_newnode, fc_tsc, TableSampleClause);
				MUTATE(fc_newnode->args, fc_tsc->args, List *);
				MUTATE(fc_newnode->repeatable, fc_tsc->repeatable, Expr *);
				return (Node *) fc_newnode;
			}
			break;
		case T_TableFunc:
			{
				TableFunc  *fc_tf = (TableFunc *) fc_node;
				TableFunc  *fc_newnode;

				FLATCOPY(fc_newnode, fc_tf, TableFunc);
				MUTATE(fc_newnode->ns_uris, fc_tf->ns_uris, List *);
				MUTATE(fc_newnode->docexpr, fc_tf->docexpr, Node *);
				MUTATE(fc_newnode->rowexpr, fc_tf->rowexpr, Node *);
				MUTATE(fc_newnode->colexprs, fc_tf->colexprs, List *);
				MUTATE(fc_newnode->coldefexprs, fc_tf->coldefexprs, List *);
				return (Node *) fc_newnode;
			}
			break;
		default:
			elog(ERROR, "unrecognized node type: %d",
				 (int) nodeTag(fc_node));
			break;
	}
	/* 不能到达这里，但让编译器开心 */
	return NULL;
}


/*
 * query_tree_mutator --- 启动修改查询的表达式
 *
 * 这个例程的存在是为了减少需要知道查询所有表达式子树的位置的地方。
 * 注意，它可以用于在查询的顶层开始遍历，而无论变异器是否打算深入子查询。
 * 它对于深入变异器中的子查询也很有用。
 *
 * 一些调用者希望抑制变异查询中的某些项目，通常是因为他们需要特殊处理它们，
 * 或者实际上不想递归进入子查询。这通过标志参数得到支持，
 * 该参数是抑制变异指定项的标志值的按位或。（可以根据需要添加更多标志位。）
 *
 * 通常，顶层查询节点本身会被复制，但一些调用者希望它原地修改；
 * 他们必须在标志中传递 QTW_DONT_COPY_QUERY。
 * 所有修改的子结构在任何情况下都是安全复制的。
 */
Query * query_tree_mutator(Query *fc_query,
				   Node *(*fc_mutator) (),
				   void *fc_context,
				   int fc_flags)
{
	Assert(fc_query != NULL && IsA(fc_query, Query));

	if (!(fc_flags & QTW_DONT_COPY_QUERY))
	{
		Query	   *fc_newquery;

		FLATCOPY(fc_newquery, fc_query, Query);
		fc_query = fc_newquery;
	}

	MUTATE(fc_query->targetList, fc_query->targetList, List *);
	MUTATE(fc_query->withCheckOptions, fc_query->withCheckOptions, List *);
	MUTATE(fc_query->onConflict, fc_query->onConflict, OnConflictExpr *);
	MUTATE(fc_query->mergeActionList, fc_query->mergeActionList, List *);
	MUTATE(fc_query->returningList, fc_query->returningList, List *);
	MUTATE(fc_query->jointree, fc_query->jointree, FromExpr *);
	MUTATE(fc_query->setOperations, fc_query->setOperations, Node *);
	MUTATE(fc_query->havingQual, fc_query->havingQual, Node *);
	MUTATE(fc_query->limitOffset, fc_query->limitOffset, Node *);
	MUTATE(fc_query->limitCount, fc_query->limitCount, Node *);

	/*
	 * 大多数调用者对 SortGroupClause 节点不感兴趣，因为它们不包含实际的表达式。
	 * 然而，它们确实包含 OID，某些变异器可能对此感兴趣。
	 */

	if ((fc_flags & QTW_EXAMINE_SORTGROUP))
	{
		MUTATE(fc_query->groupClause, fc_query->groupClause, List *);
		MUTATE(fc_query->windowClause, fc_query->windowClause, List *);
		MUTATE(fc_query->sortClause, fc_query->sortClause, List *);
		MUTATE(fc_query->distinctClause, fc_query->distinctClause, List *);
	}
	else
	{
		/*
		 * 但我们需要变异 WindowClause 节点下的表达式，即使我们对 SortGroupClause 节点
		 * 不感兴趣。
		 */
		List	   *fc_resultlist;
		ListCell   *fc_temp;

		fc_resultlist = NIL;
		foreach(fc_temp, fc_query->windowClause)
		{
			WindowClause *fc_wc = lfirst_node(WindowClause, fc_temp);
			WindowClause *fc_newnode;

			FLATCOPY(fc_newnode, fc_wc, WindowClause);
			MUTATE(fc_newnode->startOffset, fc_wc->startOffset, Node *);
			MUTATE(fc_newnode->endOffset, fc_wc->endOffset, Node *);
			MUTATE(fc_newnode->runCondition, fc_wc->runCondition, List *);

			fc_resultlist = lappend(fc_resultlist, (Node *) fc_newnode);
		}
		fc_query->windowClause = fc_resultlist;
	}

	/*
	 * groupingSets 和 rowMarks 不会被变异：
	 *
	 * groupingSets 仅包含 ressortgroup 引用（整数），没有 groupClause 或 tlist 就毫无意义。
	 * 因此，任何需要关心它们的变异器必须在其查询处理中自行处理它们。
	 *
	 * rowMarks 仅包含 rangetable 索引（以及标志等），因此在查询级别
	 * 应类似地处理。
	 */

	if (!(fc_flags & QTW_IGNORE_CTE_SUBQUERIES))
		MUTATE(fc_query->cteList, fc_query->cteList, List *);
	else						/* 否则按原样复制 CTE 列表 */
		fc_query->cteList = copyObject(fc_query->cteList);
	fc_query->rtable = range_table_mutator(fc_query->rtable,
										fc_mutator, fc_context, fc_flags);
	return fc_query;
}

/*
 * range_table_mutator 只是 query_tree_mutator 中处理查询的 rangetable 的部分。
 * 将其拆分出来是因为它单独使用时可能很有用。
 */
List * range_table_mutator(List *fc_rtable,
					Node *(*fc_mutator) (),
					void *fc_context,
					int fc_flags)
{
	List	   *fc_newrt = NIL;
	ListCell   *fc_rt;

	foreach(fc_rt, fc_rtable)
	{
		RangeTblEntry *fc_rte = (RangeTblEntry *) lfirst(fc_rt);
		RangeTblEntry *fc_newrte;

		FLATCOPY(fc_newrte, fc_rte, RangeTblEntry);
		switch (fc_rte->rtekind)
		{
			case RTE_RELATION:
				MUTATE(fc_newrte->tablesample, fc_rte->tablesample,
					   TableSampleClause *);
				/* 我们不在乎复制 eref、别名等；这样可以吗？ */
				break;
			case RTE_SUBQUERY:
				if (!(fc_flags & QTW_IGNORE_RT_SUBQUERIES))
					MUTATE(fc_newrte->subquery, fc_rte->subquery, Query *);
				else
				{
					/* 否则，按原样复制 RT 子查询 */
					fc_newrte->subquery = copyObject(fc_rte->subquery);
				}
				break;
			case RTE_JOIN:
				if (!(fc_flags & QTW_IGNORE_JOINALIASES))
					MUTATE(fc_newrte->joinaliasvars, fc_rte->joinaliasvars, List *);
				else
				{
					/* 否则，按原样复制连接别名 */
					fc_newrte->joinaliasvars = copyObject(fc_rte->joinaliasvars);
				}
				break;
			case RTE_FUNCTION:
				MUTATE(fc_newrte->functions, fc_rte->functions, List *);
				break;
			case RTE_TABLEFUNC:
				MUTATE(fc_newrte->tablefunc, fc_rte->tablefunc, TableFunc *);
				break;
			case RTE_VALUES:
				MUTATE(fc_newrte->values_lists, fc_rte->values_lists, List *);
				break;
			case RTE_CTE:
			case RTE_NAMEDTUPLESTORE:
			case RTE_RESULT:
				/* 无需操作 */
				break;
		}
		MUTATE(fc_newrte->securityQuals, fc_rte->securityQuals, List *);
		fc_newrt = lappend(fc_newrt, fc_newrte);
	}
	return fc_newrt;
}

/*
 * query_or_expression_tree_walker --- 混合形式
 *
 * 如果在 Query 节点上调用，此例程将调用 query_tree_walker，
 * 否则将直接调用 walker。这是在最外层 Query 节点上当 walker 的正常状态变化不适合时启动递归的一种有用方式。
 */
bool query_or_expression_tree_walker(Node *fc_node,
								bool (*fc_walker) (),
								void *fc_context,
								int fc_flags)
{
	if (fc_node && IsA(fc_node, Query))
		return query_tree_walker((Query *) fc_node,
								 fc_walker,
								 fc_context,
								 fc_flags);
	else
		return fc_walker(fc_node, fc_context);
}

/*
 * query_or_expression_tree_mutator --- 混合形式
 *
 * 如果在 Query 节点上调用，此例程将调用 query_tree_mutator，
 * 否则将直接调用 mutator。这是在最外层 Query 节点上当 mutator 的正常状态变化不适合时启动递归的一种有用方式。
 */
Node * query_or_expression_tree_mutator(Node *fc_node,
								 Node *(*fc_mutator) (),
								 void *fc_context,
								 int fc_flags)
{
	if (fc_node && IsA(fc_node, Query))
		return (Node *) query_tree_mutator((Query *) fc_node,
										   fc_mutator,
										   fc_context,
										   fc_flags);
	else
		return fc_mutator(fc_node, fc_context);
}


/*
 * raw_expression_tree_walker --- 遍历原始解析树
 *
 * 此接口与 expression_tree_walker 完全相同，但它不是遍历分析后的解析树，而是知道如何遍历在原始语法输出中找到的节点类型。
 * （目前没有结合 walker 的必要，因此我们为了效率将它们分开。）
 * 与 expression_tree_walker 不同的是，这里没有关于查询边界的特殊规则：我们会下去访问所有可能有趣的内容。
 *
 * 目前，这里的节点类型覆盖仅扩展到 DML 语句（SELECT/INSERT/UPDATE/DELETE/MERGE）及其可能出现的节点，
 * 因为这主要在分析 CTE 时使用，并且只有 DML 语句可以出现在 CTE 中。
 */
bool raw_expression_tree_walker(Node *fc_node,
						   bool (*fc_walker) (),
						   void *fc_context)
{
	ListCell   *fc_temp;

	/*
	 * walker 已经访问了当前节点，因此我们只需
	 * 递归到它的任何子节点中。
	 */
	if (fc_node == NULL)
		return false;

	/* 防止因过于复杂的表达式导致栈溢出 */
	check_stack_depth();

	switch (nodeTag(fc_node))
	{
		case T_SetToDefault:
		case T_CurrentOfExpr:
		case T_SQLValueFunction:
		case T_Integer:
		case T_Float:
		case T_Boolean:
		case T_String:
		case T_BitString:
		case T_ParamRef:
		case T_A_Const:
		case T_A_Star:
			/* 没有子节点的原始节点类型 */
			break;
		case T_Alias:
			/* 我们假设 colnames 列表没有趣味 */
			break;
		case T_RangeVar:
			return fc_walker(((RangeVar *) fc_node)->alias, fc_context);
		case T_GroupingFunc:
			return fc_walker(((GroupingFunc *) fc_node)->args, fc_context);
		case T_SubLink:
			{
				SubLink    *fc_sublink = (SubLink *) fc_node;

				if (fc_walker(fc_sublink->testexpr, fc_context))
					return true;
				/* 我们假设 operName 没有趣味 */
				if (fc_walker(fc_sublink->subselect, fc_context))
					return true;
			}
			break;
		case T_CaseExpr:
			{
				CaseExpr   *fc_caseexpr = (CaseExpr *) fc_node;

				if (fc_walker(fc_caseexpr->arg, fc_context))
					return true;
				/* 我们假设 walker 不关心 CaseWhens */
				foreach(fc_temp, fc_caseexpr->args)
				{
					CaseWhen   *fc_when = lfirst_node(CaseWhen, fc_temp);

					if (fc_walker(fc_when->expr, fc_context))
						return true;
					if (fc_walker(fc_when->result, fc_context))
						return true;
				}
				if (fc_walker(fc_caseexpr->defresult, fc_context))
					return true;
			}
			break;
		case T_RowExpr:
			/* 假设 colnames 不重要 */
			return fc_walker(((RowExpr *) fc_node)->args, fc_context);
		case T_CoalesceExpr:
			return fc_walker(((CoalesceExpr *) fc_node)->args, fc_context);
		case T_MinMaxExpr:
			return fc_walker(((MinMaxExpr *) fc_node)->args, fc_context);
		case T_XmlExpr:
			{
				XmlExpr    *fc_xexpr = (XmlExpr *) fc_node;

				if (fc_walker(fc_xexpr->named_args, fc_context))
					return true;
				/* 我们假设 walker 不关心 arg_names */
				if (fc_walker(fc_xexpr->args, fc_context))
					return true;
			}
			break;
		case T_NullTest:
			return fc_walker(((NullTest *) fc_node)->arg, fc_context);
		case T_BooleanTest:
			return fc_walker(((BooleanTest *) fc_node)->arg, fc_context);
		case T_JoinExpr:
			{
				JoinExpr   *fc_join = (JoinExpr *) fc_node;

				if (fc_walker(fc_join->larg, fc_context))
					return true;
				if (fc_walker(fc_join->rarg, fc_context))
					return true;
				if (fc_walker(fc_join->quals, fc_context))
					return true;
				if (fc_walker(fc_join->alias, fc_context))
					return true;
				/* 使用列表被认为无趣 */
			}
			break;
		case T_IntoClause:
			{
				IntoClause *fc_into = (IntoClause *) fc_node;

				if (fc_walker(fc_into->rel, fc_context))
					return true;
				/* colNames, options 被认为无趣 */
				/* 在原始解析树中，viewQuery 应该为 null，但需要检查 */
				if (fc_walker(fc_into->viewQuery, fc_context))
					return true;
			}
			break;
		case T_List:
			foreach(fc_temp, (List *) fc_node)
			{
				if (fc_walker((Node *) lfirst(fc_temp), fc_context))
					return true;
			}
			break;
		case T_InsertStmt:
			{
				InsertStmt *fc_stmt = (InsertStmt *) fc_node;

				if (fc_walker(fc_stmt->relation, fc_context))
					return true;
				if (fc_walker(fc_stmt->cols, fc_context))
					return true;
				if (fc_walker(fc_stmt->selectStmt, fc_context))
					return true;
				if (fc_walker(fc_stmt->onConflictClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->returningList, fc_context))
					return true;
				if (fc_walker(fc_stmt->withClause, fc_context))
					return true;
			}
			break;
		case T_DeleteStmt:
			{
				DeleteStmt *fc_stmt = (DeleteStmt *) fc_node;

				if (fc_walker(fc_stmt->relation, fc_context))
					return true;
				if (fc_walker(fc_stmt->usingClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->whereClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->returningList, fc_context))
					return true;
				if (fc_walker(fc_stmt->withClause, fc_context))
					return true;
			}
			break;
		case T_UpdateStmt:
			{
				UpdateStmt *fc_stmt = (UpdateStmt *) fc_node;

				if (fc_walker(fc_stmt->relation, fc_context))
					return true;
				if (fc_walker(fc_stmt->targetList, fc_context))
					return true;
				if (fc_walker(fc_stmt->whereClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->fromClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->returningList, fc_context))
					return true;
				if (fc_walker(fc_stmt->withClause, fc_context))
					return true;
			}
			break;
		case T_MergeStmt:
			{
				MergeStmt  *fc_stmt = (MergeStmt *) fc_node;

				if (fc_walker(fc_stmt->relation, fc_context))
					return true;
				if (fc_walker(fc_stmt->sourceRelation, fc_context))
					return true;
				if (fc_walker(fc_stmt->joinCondition, fc_context))
					return true;
				if (fc_walker(fc_stmt->mergeWhenClauses, fc_context))
					return true;
				if (fc_walker(fc_stmt->withClause, fc_context))
					return true;
			}
			break;
		case T_MergeWhenClause:
			{
				MergeWhenClause *fc_mergeWhenClause = (MergeWhenClause *) fc_node;

				if (fc_walker(fc_mergeWhenClause->condition, fc_context))
					return true;
				if (fc_walker(fc_mergeWhenClause->targetList, fc_context))
					return true;
				if (fc_walker(fc_mergeWhenClause->values, fc_context))
					return true;
			}
			break;
		case T_SelectStmt:
			{
				SelectStmt *fc_stmt = (SelectStmt *) fc_node;

				if (fc_walker(fc_stmt->distinctClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->intoClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->targetList, fc_context))
					return true;
				if (fc_walker(fc_stmt->fromClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->whereClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->groupClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->havingClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->windowClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->valuesLists, fc_context))
					return true;
				if (fc_walker(fc_stmt->sortClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->limitOffset, fc_context))
					return true;
				if (fc_walker(fc_stmt->limitCount, fc_context))
					return true;
				if (fc_walker(fc_stmt->lockingClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->withClause, fc_context))
					return true;
				if (fc_walker(fc_stmt->larg, fc_context))
					return true;
				if (fc_walker(fc_stmt->rarg, fc_context))
					return true;
			}
			break;
		case T_PLAssignStmt:
			{
				PLAssignStmt *fc_stmt = (PLAssignStmt *) fc_node;

				if (fc_walker(fc_stmt->indirection, fc_context))
					return true;
				if (fc_walker(fc_stmt->val, fc_context))
					return true;
			}
			break;
		case T_A_Expr:
			{
				A_Expr	   *fc_expr = (A_Expr *) fc_node;

				if (fc_walker(fc_expr->lexpr, fc_context))
					return true;
				if (fc_walker(fc_expr->rexpr, fc_context))
					return true;
				/* 操作符名称被认为无趣 */
			}
			break;
		case T_BoolExpr:
			{
				BoolExpr   *fc_expr = (BoolExpr *) fc_node;

				if (fc_walker(fc_expr->args, fc_context))
					return true;
			}
			break;
		case T_ColumnRef:
			/* 我们假设字段不包含任何有趣的内容 */
			break;
		case T_FuncCall:
			{
				FuncCall   *fc_fcall = (FuncCall *) fc_node;

				if (fc_walker(fc_fcall->args, fc_context))
					return true;
				if (fc_walker(fc_fcall->agg_order, fc_context))
					return true;
				if (fc_walker(fc_fcall->agg_filter, fc_context))
					return true;
				if (fc_walker(fc_fcall->over, fc_context))
					return true;
				/* 函数名称被认为无趣 */
			}
			break;
		case T_NamedArgExpr:
			return fc_walker(((NamedArgExpr *) fc_node)->arg, fc_context);
		case T_A_Indices:
			{
				A_Indices  *fc_indices = (A_Indices *) fc_node;

				if (fc_walker(fc_indices->lidx, fc_context))
					return true;
				if (fc_walker(fc_indices->uidx, fc_context))
					return true;
			}
			break;
		case T_A_Indirection:
			{
				A_Indirection *fc_indir = (A_Indirection *) fc_node;

				if (fc_walker(fc_indir->arg, fc_context))
					return true;
				if (fc_walker(fc_indir->indirection, fc_context))
					return true;
			}
			break;
		case T_A_ArrayExpr:
			return fc_walker(((A_ArrayExpr *) fc_node)->elements, fc_context);
		case T_ResTarget:
			{
				ResTarget  *fc_rt = (ResTarget *) fc_node;

				if (fc_walker(fc_rt->indirection, fc_context))
					return true;
				if (fc_walker(fc_rt->val, fc_context))
					return true;
			}
			break;
		case T_MultiAssignRef:
			return fc_walker(((MultiAssignRef *) fc_node)->source, fc_context);
		case T_TypeCast:
			{
				TypeCast   *fc_tc = (TypeCast *) fc_node;

				if (fc_walker(fc_tc->arg, fc_context))
					return true;
				if (fc_walker(fc_tc->typeName, fc_context))
					return true;
			}
			break;
		case T_CollateClause:
			return fc_walker(((CollateClause *) fc_node)->arg, fc_context);
		case T_SortBy:
			return fc_walker(((SortBy *) fc_node)->node, fc_context);
		case T_WindowDef:
			{
				WindowDef  *fc_wd = (WindowDef *) fc_node;

				if (fc_walker(fc_wd->partitionClause, fc_context))
					return true;
				if (fc_walker(fc_wd->orderClause, fc_context))
					return true;
				if (fc_walker(fc_wd->startOffset, fc_context))
					return true;
				if (fc_walker(fc_wd->endOffset, fc_context))
					return true;
			}
			break;
		case T_RangeSubselect:
			{
				RangeSubselect *fc_rs = (RangeSubselect *) fc_node;

				if (fc_walker(fc_rs->subquery, fc_context))
					return true;
				if (fc_walker(fc_rs->alias, fc_context))
					return true;
			}
			break;
		case T_RangeFunction:
			{
				RangeFunction *fc_rf = (RangeFunction *) fc_node;

				if (fc_walker(fc_rf->functions, fc_context))
					return true;
				if (fc_walker(fc_rf->alias, fc_context))
					return true;
				if (fc_walker(fc_rf->coldeflist, fc_context))
					return true;
			}
			break;
		case T_RangeTableSample:
			{
				RangeTableSample *fc_rts = (RangeTableSample *) fc_node;

				if (fc_walker(fc_rts->relation, fc_context))
					return true;
				/* 方法名称被认为无趣 */
				if (fc_walker(fc_rts->args, fc_context))
					return true;
				if (fc_walker(fc_rts->repeatable, fc_context))
					return true;
			}
			break;
		case T_RangeTableFunc:
			{
				RangeTableFunc *fc_rtf = (RangeTableFunc *) fc_node;

				if (fc_walker(fc_rtf->docexpr, fc_context))
					return true;
				if (fc_walker(fc_rtf->rowexpr, fc_context))
					return true;
				if (fc_walker(fc_rtf->namespaces, fc_context))
					return true;
				if (fc_walker(fc_rtf->columns, fc_context))
					return true;
				if (fc_walker(fc_rtf->alias, fc_context))
					return true;
			}
			break;
		case T_RangeTableFuncCol:
			{
				RangeTableFuncCol *fc_rtfc = (RangeTableFuncCol *) fc_node;

				if (fc_walker(fc_rtfc->colexpr, fc_context))
					return true;
				if (fc_walker(fc_rtfc->coldefexpr, fc_context))
					return true;
			}
			break;
		case T_TypeName:
			{
				TypeName   *fc_tn = (TypeName *) fc_node;

				if (fc_walker(fc_tn->typmods, fc_context))
					return true;
				if (fc_walker(fc_tn->arrayBounds, fc_context))
					return true;
				/* 类型名称本身被认为无趣 */
			}
			break;
		case T_ColumnDef:
			{
				ColumnDef  *fc_coldef = (ColumnDef *) fc_node;

				if (fc_walker(fc_coldef->typeName, fc_context))
					return true;
				if (fc_walker(fc_coldef->raw_default, fc_context))
					return true;
				if (fc_walker(fc_coldef->collClause, fc_context))
					return true;
				/* 目前，约束被忽略 */
			}
			break;
		case T_IndexElem:
			{
				IndexElem  *fc_indelem = (IndexElem *) fc_node;

				if (fc_walker(fc_indelem->expr, fc_context))
					return true;
				/* 排序规则和操作类名称被认为无趣 */
			}
			break;
		case T_GroupingSet:
			return fc_walker(((GroupingSet *) fc_node)->content, fc_context);
		case T_LockingClause:
			return fc_walker(((LockingClause *) fc_node)->lockedRels, fc_context);
		case T_XmlSerialize:
			{
				XmlSerialize *fc_xs = (XmlSerialize *) fc_node;

				if (fc_walker(fc_xs->expr, fc_context))
					return true;
				if (fc_walker(fc_xs->typeName, fc_context))
					return true;
			}
			break;
		case T_WithClause:
			return fc_walker(((WithClause *) fc_node)->ctes, fc_context);
		case T_InferClause:
			{
				InferClause *fc_stmt = (InferClause *) fc_node;

				if (fc_walker(fc_stmt->indexElems, fc_context))
					return true;
				if (fc_walker(fc_stmt->whereClause, fc_context))
					return true;
			}
			break;
		case T_OnConflictClause:
			{
				OnConflictClause *fc_stmt = (OnConflictClause *) fc_node;

				if (fc_walker(fc_stmt->infer, fc_context))
					return true;
				if (fc_walker(fc_stmt->targetList, fc_context))
					return true;
				if (fc_walker(fc_stmt->whereClause, fc_context))
					return true;
			}
			break;
		case T_CommonTableExpr:
			/* search_clause 和 cycle_clause 在这里不有趣 */
			return fc_walker(((CommonTableExpr *) fc_node)->ctequery, fc_context);
		default:
			elog(ERROR, "unrecognized node type: %d",
				 (int) nodeTag(fc_node));
			break;
	}
	return false;
}

/*
 * planstate_tree_walker --- 遍历计划状态树
 *
 * walker 已经访问了当前节点，因此我们只需
 * 递归到它的任何子节点中。
 */
bool planstate_tree_walker(PlanState *fc_planstate,
					  bool (*fc_walker) (),
					  void *fc_context)
{
	Plan	   *fc_plan = fc_planstate->plan;
	ListCell   *fc_lc;

	/* 防止因过于复杂的计划树导致堆栈溢出 */
	check_stack_depth();

	/* initPlan-s */
	if (fc_planstate_walk_subplans(fc_planstate->initPlan, fc_walker, fc_context))
		return true;

	/* lefttree */
	if (outerPlanState(fc_planstate))
	{
		if (fc_walker(outerPlanState(fc_planstate), fc_context))
			return true;
	}

	/* righttree */
	if (innerPlanState(fc_planstate))
	{
		if (fc_walker(innerPlanState(fc_planstate), fc_context))
			return true;
	}

	/* 特殊子计划 */
	switch (nodeTag(fc_plan))
	{
		case T_Append:
			if (fc_planstate_walk_members(((AppendState *) fc_planstate)->appendplans,
									   ((AppendState *) fc_planstate)->as_nplans,
									   fc_walker, fc_context))
				return true;
			break;
		case T_MergeAppend:
			if (fc_planstate_walk_members(((MergeAppendState *) fc_planstate)->mergeplans,
									   ((MergeAppendState *) fc_planstate)->ms_nplans,
									   fc_walker, fc_context))
				return true;
			break;
		case T_BitmapAnd:
			if (fc_planstate_walk_members(((BitmapAndState *) fc_planstate)->bitmapplans,
									   ((BitmapAndState *) fc_planstate)->nplans,
									   fc_walker, fc_context))
				return true;
			break;
		case T_BitmapOr:
			if (fc_planstate_walk_members(((BitmapOrState *) fc_planstate)->bitmapplans,
									   ((BitmapOrState *) fc_planstate)->nplans,
									   fc_walker, fc_context))
				return true;
			break;
		case T_SubqueryScan:
			if (fc_walker(((SubqueryScanState *) fc_planstate)->subplan, fc_context))
				return true;
			break;
		case T_CustomScan:
			foreach(fc_lc, ((CustomScanState *) fc_planstate)->custom_ps)
			{
				if (fc_walker((PlanState *) lfirst(fc_lc), fc_context))
					return true;
			}
			break;
		default:
			break;
	}

	/* subPlan-s */
	if (fc_planstate_walk_subplans(fc_planstate->subPlan, fc_walker, fc_context))
		return true;

	return false;
}

/*
 * 遍历一组 SubPlans（或 initPlans，这也使用 SubPlan 节点）。
 */
static bool fc_planstate_walk_subplans(List *fc_plans,
						bool (*fc_walker) (),
						void *fc_context)
{
	ListCell   *fc_lc;

	foreach(fc_lc, fc_plans)
	{
		SubPlanState *fc_sps = lfirst_node(SubPlanState, fc_lc);

		if (fc_walker(fc_sps->planstate, fc_context))
			return true;
	}

	return false;
}

/*
 * 遍历 ModifyTable、Append、MergeAppend、
 * BitmapAnd 或 BitmapOr 节点的组成计划。
 */
static bool fc_planstate_walk_members(PlanState **fc_planstates, int fc_nplans,
					   bool (*fc_walker) (), void *fc_context)
{
	int			fc_j;

	for (fc_j = 0; fc_j < fc_nplans; fc_j++)
	{
		if (fc_walker(fc_planstates[fc_j], fc_context))
			return true;
	}

	return false;
}
